From 8a8896f47760d7da1c211107452130cda1b802ba Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Fri, 13 May 2016 16:14:19 +0100 Subject: [PATCH] kernel: Update Hyper-V socket patch to v10 This required pulling in the Qualcom IPC patches as those changed the socket family enumeration. All other patches should be the same. Signed-off-by: Rolf Neugebauer --- ...make-find_vqs-checkpatch.pl-friendly.patch | 10 +- ...vmci_transport_notify_ops-structures.patch | 6 +- ...the-area-influenced-by-prepare_to_wa.patch | 6 +- ...t-specific-vsock_transport-functions.patch | 6 +- ...OCK-Introduce-virtio_vsock_common.ko.patch | 46 +- ...-VSOCK-Introduce-virtio_transport.ko.patch | 26 +- .../0007-VSOCK-Introduce-vhost_vsock.ko.patch | 37 +- .../0008-VSOCK-Add-Makefile-and-Kconfig.patch | 16 +- ...-host-network-namespace-to-use-AF_VS.patch | 6 +- ...-serialize-process_chn_event-and-vmb.patch | 6 +- ...-do-sanity-check-of-channel-state-in.patch | 6 +- ...-fix-rescind-offer-handling-for-devi.patch | 6 +- ...-release-relid-on-error-in-vmbus_pro.patch | 6 +- ...-channge-vmbus_connection.channel_lo.patch | 6 +- ...-add-a-helper-function-to-set-a-chan.patch | 6 +- ...-define-the-new-offer-type-for-Hyper.patch | 6 +- ...-vmbus_sendpacket_ctl-hvsock-avoid-u.patch | 6 +- ...-define-a-new-VMBus-message-type-for.patch | 6 +- ...-add-a-hvsock-flag-in-struct-hv_driv.patch | 6 +- ...s-add-a-per-channel-rescind-callback.patch | 6 +- ...-add-an-API-vmbus_hvsock_device_unre.patch | 6 +- ...Kernel-Connection-Multiplexor-module.patch | 29 +- ...AF_KCM-entries-to-family-name-tables.patch | 6 +- .../0024-net-Add-Qualcomm-IPC-router.patch | 1307 +++++++++++++++++ ...5-hv_sock-introduce-Hyper-V-Sockets.patch} | 899 ++++++------ ...YPERV-entries-to-family-name-tables.patch} | 6 +- ...onnect-socket-when-peer-has-shutdow.patch} | 6 +- 27 files changed, 1869 insertions(+), 615 deletions(-) create mode 100644 alpine/kernel/patches/0024-net-Add-Qualcomm-IPC-router.patch rename alpine/kernel/patches/{0024-hv_sock-introduce-Hyper-V-Sockets.patch => 0025-hv_sock-introduce-Hyper-V-Sockets.patch} (78%) rename alpine/kernel/patches/{0025-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch => 0026-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch} (93%) rename alpine/kernel/patches/{0026-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch => 0027-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch} (93%) diff --git a/alpine/kernel/patches/0001-virtio-make-find_vqs-checkpatch.pl-friendly.patch b/alpine/kernel/patches/0001-virtio-make-find_vqs-checkpatch.pl-friendly.patch index 201f40f35..181feb2f7 100644 --- a/alpine/kernel/patches/0001-virtio-make-find_vqs-checkpatch.pl-friendly.patch +++ b/alpine/kernel/patches/0001-virtio-make-find_vqs-checkpatch.pl-friendly.patch @@ -1,7 +1,7 @@ -From d8f7730e3211cdb16cd9d26143121aeb05f22509 Mon Sep 17 00:00:00 2001 +From 4eb420ca189539397da818a6f0dab9f187693681 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Dec 2015 16:53:43 +0800 -Subject: [PATCH 01/26] virtio: make find_vqs() checkpatch.pl-friendly +Subject: [PATCH 01/27] virtio: make find_vqs() checkpatch.pl-friendly checkpatch.pl wants arrays of strings declared as follows: @@ -189,10 +189,10 @@ index b976d96..2cc2522 100644 /* Setup the affinity for a virtqueue: diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c -index 8e5cf19..c0c11fa 100644 +index 4469202..631021c 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c -@@ -418,7 +418,7 @@ err_new_queue: +@@ -423,7 +423,7 @@ err_new_queue: static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], @@ -215,5 +215,5 @@ index e5ce8ab..6e6cb0c 100644 u64 (*get_features)(struct virtio_device *vdev); int (*finalize_features)(struct virtio_device *vdev); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0002-VSOCK-constify-vmci_transport_notify_ops-structures.patch b/alpine/kernel/patches/0002-VSOCK-constify-vmci_transport_notify_ops-structures.patch index 51b92a935..33fef4562 100644 --- a/alpine/kernel/patches/0002-VSOCK-constify-vmci_transport_notify_ops-structures.patch +++ b/alpine/kernel/patches/0002-VSOCK-constify-vmci_transport_notify_ops-structures.patch @@ -1,7 +1,7 @@ -From 0260029492a1503e871236767ed86e2fc3862cc2 Mon Sep 17 00:00:00 2001 +From 55b1d9c5700491a520e9f62db00813153949038e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 Nov 2015 18:39:17 +0100 -Subject: [PATCH 02/26] VSOCK: constify vmci_transport_notify_ops structures +Subject: [PATCH 02/27] VSOCK: constify vmci_transport_notify_ops structures The vmci_transport_notify_ops structures are never modified, so declare them as const. @@ -73,5 +73,5 @@ index dc9c792..21e591d 100644 vmci_transport_notify_pkt_socket_destruct, vmci_transport_notify_pkt_poll_in, -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0003-AF_VSOCK-Shrink-the-area-influenced-by-prepare_to_wa.patch b/alpine/kernel/patches/0003-AF_VSOCK-Shrink-the-area-influenced-by-prepare_to_wa.patch index 50b7422b8..7fd6c21fe 100644 --- a/alpine/kernel/patches/0003-AF_VSOCK-Shrink-the-area-influenced-by-prepare_to_wa.patch +++ b/alpine/kernel/patches/0003-AF_VSOCK-Shrink-the-area-influenced-by-prepare_to_wa.patch @@ -1,7 +1,7 @@ -From 6a585c01a353551a69af45bf31606f13115480d1 Mon Sep 17 00:00:00 2001 +From 7344b208b2e3dc6283addd17ac444d0e6f086b3c Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 22 Mar 2016 17:05:52 +0100 -Subject: [PATCH 03/26] AF_VSOCK: Shrink the area influenced by prepare_to_wait +Subject: [PATCH 03/27] AF_VSOCK: Shrink the area influenced by prepare_to_wait When a thread is prepared for waiting by calling prepare_to_wait, sleeping is not allowed until either the wait has taken place or finish_wait has @@ -332,5 +332,5 @@ index 7fd1220..3dce53e 100644 release_sock(sk); return err; -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0004-VSOCK-transport-specific-vsock_transport-functions.patch b/alpine/kernel/patches/0004-VSOCK-transport-specific-vsock_transport-functions.patch index e42b7f510..232b21b42 100644 --- a/alpine/kernel/patches/0004-VSOCK-transport-specific-vsock_transport-functions.patch +++ b/alpine/kernel/patches/0004-VSOCK-transport-specific-vsock_transport-functions.patch @@ -1,7 +1,7 @@ -From a3f136168f164f66de1de277a08b76f54b289d5a Mon Sep 17 00:00:00 2001 +From 0397651ccfc37e24cc6c9ef3c6356e269e9e961f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Dec 2015 11:10:21 +0800 -Subject: [PATCH 04/26] VSOCK: transport-specific vsock_transport functions +Subject: [PATCH 04/27] VSOCK: transport-specific vsock_transport functions struct vsock_transport contains function pointers called by AF_VSOCK core code. The transport may want its own transport-specific function @@ -54,5 +54,5 @@ index 3dce53e..112fa8b 100644 MODULE_DESCRIPTION("VMware Virtual Socket Family"); MODULE_VERSION("1.0.1.0-k"); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0005-VSOCK-Introduce-virtio_vsock_common.ko.patch b/alpine/kernel/patches/0005-VSOCK-Introduce-virtio_vsock_common.ko.patch index 03045723d..fa464bc2e 100644 --- a/alpine/kernel/patches/0005-VSOCK-Introduce-virtio_vsock_common.ko.patch +++ b/alpine/kernel/patches/0005-VSOCK-Introduce-virtio_vsock_common.ko.patch @@ -1,49 +1,13 @@ -From 4018aa8a812fd6f1a64e3d227550bf5752127314 Mon Sep 17 00:00:00 2001 +From 397a1c318aa57643a35b048ae9e9df10fb7c46cf Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 13 Jun 2013 18:27:00 +0800 -Subject: [PATCH 05/26] VSOCK: Introduce virtio_vsock_common.ko +Subject: [PATCH 05/27] VSOCK: Introduce virtio_vsock_common.ko This module contains the common code and header files for the following virtio_transporto and vhost_vsock kernel modules. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi ---- -v5: - * Add event virtqueue, struct virtio_vsock_event, and transport reset - event - * Reorder virtqueue indices: rx, tx, event - * Drop unused virtqueue_pairs config field - * Drop unused ctrl virtqueue - * Switch to a free virtio device ID, the previous one was reserved -v4: - * Add MAINTAINERS file entry - * checkpatch.pl cleanups - * linux_vsock.h: drop wrong copy-pasted license header - * Move tx sock refcounting to virtio_transport_alloc/free_pkt() to fix - leaks in error paths - * Add send_pkt_no_sock() to send RST packets with no listen socket - * Rename per-socket state from virtio_transport to virtio_vsock_sock - * Move send_pkt_ops to new virtio_transport struct - * Drop dumppkt function, packet capture will be added in the future - * Drop empty virtio_transport_dec_tx_pkt() - * Allow guest->host connections again - * Use trace events instead of pr_debug() -v3: - * Remove unnecessary 3-way handshake, just do REQUEST/RESPONSE instead - of REQUEST/RESPONSE/ACK - * Remove SOCK_DGRAM support and focus on SOCK_STREAM first - * Only allow host->guest connections (same security model as latest - VMware) -v2: - * Fix peer_buf_alloc inheritance on child socket - * Notify other side of SOCK_STREAM disconnect (fixes shutdown - semantics) - * Avoid recursive mutex_lock(tx_lock) for write_space (fixes deadlock) - * Define VIRTIO_VSOCK_TYPE_STREAM/DGRAM hardware interface constants - * Define VIRTIO_VSOCK_SHUTDOWN_RCV/SEND hardware interface constants - -(cherry picked from commit 83ac0f5ff6c9faf03050a4c77b3d7a96afe53402) --- MAINTAINERS | 10 + include/linux/virtio_vsock.h | 167 ++++ @@ -58,10 +22,10 @@ v2: create mode 100644 net/vmw_vsock/virtio_transport_common.c diff --git a/MAINTAINERS b/MAINTAINERS -index 65bf152..fab150d 100644 +index 4c3e1d2..aa88662 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11395,6 +11395,16 @@ S: Maintained +@@ -11382,6 +11382,16 @@ S: Maintained F: drivers/media/v4l2-core/videobuf2-* F: include/media/videobuf2-* @@ -1357,5 +1321,5 @@ index 0000000..5b9e202 +MODULE_AUTHOR("Asias He"); +MODULE_DESCRIPTION("common code for virtio vsock"); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0006-VSOCK-Introduce-virtio_transport.ko.patch b/alpine/kernel/patches/0006-VSOCK-Introduce-virtio_transport.ko.patch index 744844a9b..3be8e74d2 100644 --- a/alpine/kernel/patches/0006-VSOCK-Introduce-virtio_transport.ko.patch +++ b/alpine/kernel/patches/0006-VSOCK-Introduce-virtio_transport.ko.patch @@ -1,29 +1,13 @@ -From ccaac837ceb4a9582bb57f71e0cac791f7336b19 Mon Sep 17 00:00:00 2001 +From bfa67b1c19a075f4fbb89fd393e9c368ad156416 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 13 Jun 2013 18:28:48 +0800 -Subject: [PATCH 06/26] VSOCK: Introduce virtio_transport.ko +Subject: [PATCH 06/27] VSOCK: Introduce virtio_transport.ko VM sockets virtio transport implementation. This driver runs in the guest. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi ---- -v5: - * Add transport reset event handling - * Drop ctrl virtqueue -v4: - * Add MAINTAINERS file entry - * Drop short/long rx packets - * checkpatch.pl cleanups - * Clarify locking in struct virtio_vsock - * Narrow local variable scopes as suggested by Alex Bennee - * Call wake_up() after decrementing total_tx_buf to avoid deadlock -v2: - * Fix total_tx_buf accounting - * Add virtio_transport global mutex to prevent races - -(cherry picked from commit 1b5c3d05a4c0c1dc87d29d3bee701cf1c84cd5d3) --- MAINTAINERS | 1 + net/vmw_vsock/virtio_transport.c | 584 +++++++++++++++++++++++++++++++++++++++ @@ -31,10 +15,10 @@ v2: create mode 100644 net/vmw_vsock/virtio_transport.c diff --git a/MAINTAINERS b/MAINTAINERS -index fab150d..403c4cc 100644 +index aa88662..889d0d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11404,6 +11404,7 @@ S: Maintained +@@ -11391,6 +11391,7 @@ S: Maintained F: include/linux/virtio_vsock.h F: include/uapi/linux/virtio_vsock.h F: net/vmw_vsock/virtio_transport_common.c @@ -633,5 +617,5 @@ index 0000000..45472e0 +MODULE_DESCRIPTION("virtio transport for vsock"); +MODULE_DEVICE_TABLE(virtio, id_table); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0007-VSOCK-Introduce-vhost_vsock.ko.patch b/alpine/kernel/patches/0007-VSOCK-Introduce-vhost_vsock.ko.patch index 74bcf979c..68d681f53 100644 --- a/alpine/kernel/patches/0007-VSOCK-Introduce-vhost_vsock.ko.patch +++ b/alpine/kernel/patches/0007-VSOCK-Introduce-vhost_vsock.ko.patch @@ -1,40 +1,13 @@ -From f52efbc874c742a671939ea6408c59545025007d Mon Sep 17 00:00:00 2001 +From a40b8961e92a5cfea634685e0e3aff9227a0fdd5 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 13 Jun 2013 18:29:21 +0800 -Subject: [PATCH 07/26] VSOCK: Introduce vhost_vsock.ko +Subject: [PATCH 07/27] VSOCK: Introduce vhost_vsock.ko VM sockets vhost transport implementation. This driver runs on the host. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi ---- -v5: - * Only take rx/tx virtqueues, userspace handles the other virtqueues - * Explicitly skip instances without a CID when transferring packets - * Add VHOST_VSOCK_START ioctl to being vhost virtqueue processing - * Reset established connections when device is closed -v4: - * Add MAINTAINERS file entry - * virtqueue used len is now sizeof(pkt->hdr) + pkt->len instead of just - pkt->len - * checkpatch.pl cleanups - * Clarify struct vhost_vsock locking - * Add comments about optimization that disables virtqueue notify - * Drop unused vhost_vsock_handle_ctl_kick() - * Call wake_up() after decrementing total_tx_buf to prevent deadlock -v3: - * Remove unneeded variable used to store return value - (Fengguang Wu and Julia Lawall - ) -v2: - * Add missing total_tx_buf decrement - * Support flexible rx/tx descriptor layout - * Refuse to assign reserved CIDs - * Refuse guest CID if already in use - * Only accept correctly addressed packets - -(cherry picked from commit 40d1901b66f0250e91094df07955edf57cf2f41e) --- MAINTAINERS | 2 + drivers/vhost/vsock.c | 694 ++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -44,10 +17,10 @@ v2: create mode 100644 drivers/vhost/vsock.h diff --git a/MAINTAINERS b/MAINTAINERS -index 403c4cc..530bce8 100644 +index 889d0d7..9a70d2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11405,6 +11405,8 @@ F: include/linux/virtio_vsock.h +@@ -11392,6 +11392,8 @@ F: include/linux/virtio_vsock.h F: include/uapi/linux/virtio_vsock.h F: net/vmw_vsock/virtio_transport_common.c F: net/vmw_vsock/virtio_transport.c @@ -768,5 +741,5 @@ index 0000000..173f9fc +#define VHOST_VSOCK_START _IO(VHOST_VIRTIO, 0x61) +#endif -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0008-VSOCK-Add-Makefile-and-Kconfig.patch b/alpine/kernel/patches/0008-VSOCK-Add-Makefile-and-Kconfig.patch index ad379b4ee..4302c835b 100644 --- a/alpine/kernel/patches/0008-VSOCK-Add-Makefile-and-Kconfig.patch +++ b/alpine/kernel/patches/0008-VSOCK-Add-Makefile-and-Kconfig.patch @@ -1,22 +1,12 @@ -From e8c8f5299fd202db5d56a10f1dc0a4e464e9a211 Mon Sep 17 00:00:00 2001 +From f0c236fefc57085cb6de93b4af6a97f794d86944 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 13 Jun 2013 18:30:19 +0800 -Subject: [PATCH 08/26] VSOCK: Add Makefile and Kconfig +Subject: [PATCH 08/27] VSOCK: Add Makefile and Kconfig Enable virtio-vsock and vhost-vsock. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi ---- -v4: - * Make checkpatch.pl happy with longer option description - * Clarify dependency on virtio rather than QEMU as suggested by Alex - Bennee -v3: - * Don't put vhost vsock driver into staging - * Add missing Kconfig dependencies (Arnd Bergmann ) - -(cherry picked from commit 4c9d2a6be1c69ec22f8ee90bb4a5cc21d3848077) --- drivers/vhost/Kconfig | 15 +++++++++++++++ drivers/vhost/Makefile | 4 ++++ @@ -104,5 +94,5 @@ index 2ce52d7..cf4c294 100644 vsock-y += af_vsock.o vsock_addr.o -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0009-VSOCK-Only-allow-host-network-namespace-to-use-AF_VS.patch b/alpine/kernel/patches/0009-VSOCK-Only-allow-host-network-namespace-to-use-AF_VS.patch index dbc135811..d6c47298d 100644 --- a/alpine/kernel/patches/0009-VSOCK-Only-allow-host-network-namespace-to-use-AF_VS.patch +++ b/alpine/kernel/patches/0009-VSOCK-Only-allow-host-network-namespace-to-use-AF_VS.patch @@ -1,7 +1,7 @@ -From 550ec4c8f90f2bf99c1bcb13b2f8476780f42418 Mon Sep 17 00:00:00 2001 +From bb208cf070af4f831073ded2ae58e624ee965105 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 4 Apr 2016 14:50:10 +0100 -Subject: [PATCH 09/26] VSOCK: Only allow host network namespace to use +Subject: [PATCH 09/27] VSOCK: Only allow host network namespace to use AF_VSOCK. The VSOCK addressing schema does not really lend itself to simply creating an @@ -27,5 +27,5 @@ index 112fa8b..ead5127 100644 return -EINVAL; -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0010-Drivers-hv-vmbus-serialize-process_chn_event-and-vmb.patch b/alpine/kernel/patches/0010-Drivers-hv-vmbus-serialize-process_chn_event-and-vmb.patch index 0426c1302..a85eb9a20 100644 --- a/alpine/kernel/patches/0010-Drivers-hv-vmbus-serialize-process_chn_event-and-vmb.patch +++ b/alpine/kernel/patches/0010-Drivers-hv-vmbus-serialize-process_chn_event-and-vmb.patch @@ -1,7 +1,7 @@ -From 1f7906c43fe139e15c19f35a4493a7ca61a6463f Mon Sep 17 00:00:00 2001 +From c30350ee4aaaf29604fc6f3f3f9bdcef2f4fdb2a Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:47 -0800 -Subject: [PATCH 10/26] Drivers: hv: vmbus: serialize process_chn_event() and +Subject: [PATCH 10/27] Drivers: hv: vmbus: serialize process_chn_event() and vmbus_close_internal() process_chn_event(), running in the tasklet, can race with @@ -83,5 +83,5 @@ index 9098f13..6a90c69 100644 } -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0011-Drivers-hv-vmbus-do-sanity-check-of-channel-state-in.patch b/alpine/kernel/patches/0011-Drivers-hv-vmbus-do-sanity-check-of-channel-state-in.patch index 02f2e76fe..5125d59c5 100644 --- a/alpine/kernel/patches/0011-Drivers-hv-vmbus-do-sanity-check-of-channel-state-in.patch +++ b/alpine/kernel/patches/0011-Drivers-hv-vmbus-do-sanity-check-of-channel-state-in.patch @@ -1,7 +1,7 @@ -From 00375a20748490730b2f004bfe44e83abecec5f1 Mon Sep 17 00:00:00 2001 +From 3aeadb59ed3d6216976648b3aee9b1db2c64c752 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:48 -0800 -Subject: [PATCH 11/26] Drivers: hv: vmbus: do sanity check of channel state in +Subject: [PATCH 11/27] Drivers: hv: vmbus: do sanity check of channel state in vmbus_close_internal() This fixes an incorrect assumption of channel state in the function. @@ -38,5 +38,5 @@ index 6a90c69..b3c14ca 100644 channel->sc_creation_callback = NULL; /* Stop callback and cancel the timer asap */ -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0012-Drivers-hv-vmbus-fix-rescind-offer-handling-for-devi.patch b/alpine/kernel/patches/0012-Drivers-hv-vmbus-fix-rescind-offer-handling-for-devi.patch index 9d7808c10..e26bdd313 100644 --- a/alpine/kernel/patches/0012-Drivers-hv-vmbus-fix-rescind-offer-handling-for-devi.patch +++ b/alpine/kernel/patches/0012-Drivers-hv-vmbus-fix-rescind-offer-handling-for-devi.patch @@ -1,7 +1,7 @@ -From 53cd041cabf572ec98d5b911abfff1a3baf1ccaa Mon Sep 17 00:00:00 2001 +From c1709827403ac4f3858b2ae0a9ee23733054b896 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:49 -0800 -Subject: [PATCH 12/26] Drivers: hv: vmbus: fix rescind-offer handling for +Subject: [PATCH 12/27] Drivers: hv: vmbus: fix rescind-offer handling for device without a driver In the path vmbus_onoffer_rescind() -> vmbus_device_unregister() -> @@ -118,5 +118,5 @@ index f19b6f7..7e46a48 100644 } -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0013-Drivers-hv-vmbus-release-relid-on-error-in-vmbus_pro.patch b/alpine/kernel/patches/0013-Drivers-hv-vmbus-release-relid-on-error-in-vmbus_pro.patch index abb081b1f..909d31ef0 100644 --- a/alpine/kernel/patches/0013-Drivers-hv-vmbus-release-relid-on-error-in-vmbus_pro.patch +++ b/alpine/kernel/patches/0013-Drivers-hv-vmbus-release-relid-on-error-in-vmbus_pro.patch @@ -1,7 +1,7 @@ -From 613d19efd48c06602018c0e7c6b4bf8d191105cd Mon Sep 17 00:00:00 2001 +From 84a3cd7026e12d7bd88f9b896df40148236af875 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:50 -0800 -Subject: [PATCH 13/26] Drivers: hv: vmbus: release relid on error in +Subject: [PATCH 13/27] Drivers: hv: vmbus: release relid on error in vmbus_process_offer() We want to simplify vmbus_onoffer_rescind() by not invoking @@ -70,5 +70,5 @@ index bd2e9f6..df76a71 100644 } -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0014-Drivers-hv-vmbus-channge-vmbus_connection.channel_lo.patch b/alpine/kernel/patches/0014-Drivers-hv-vmbus-channge-vmbus_connection.channel_lo.patch index 840c548a5..c1d8af355 100644 --- a/alpine/kernel/patches/0014-Drivers-hv-vmbus-channge-vmbus_connection.channel_lo.patch +++ b/alpine/kernel/patches/0014-Drivers-hv-vmbus-channge-vmbus_connection.channel_lo.patch @@ -1,7 +1,7 @@ -From b9a136e91171bea99a140195ccb4bbea2a65551d Mon Sep 17 00:00:00 2001 +From 567b486c7ee1eddf6aee005103b801cd9508057f Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:51 -0800 -Subject: [PATCH 14/26] Drivers: hv: vmbus: channge +Subject: [PATCH 14/27] Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex spinlock is unnecessary here. @@ -112,5 +112,5 @@ index 3782636..d9937be 100644 struct workqueue_struct *work_queue; }; -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0015-Drivers-hv-vmbus-add-a-helper-function-to-set-a-chan.patch b/alpine/kernel/patches/0015-Drivers-hv-vmbus-add-a-helper-function-to-set-a-chan.patch index 6ffd453fc..db197ede5 100644 --- a/alpine/kernel/patches/0015-Drivers-hv-vmbus-add-a-helper-function-to-set-a-chan.patch +++ b/alpine/kernel/patches/0015-Drivers-hv-vmbus-add-a-helper-function-to-set-a-chan.patch @@ -1,7 +1,7 @@ -From 37e0f1616a680b0b209c3555812c0691dacd74e0 Mon Sep 17 00:00:00 2001 +From fa129d6856d2fb887a124bb17ac88f18e3fb639f Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:37 -0800 -Subject: [PATCH 15/26] Drivers: hv: vmbus: add a helper function to set a +Subject: [PATCH 15/27] Drivers: hv: vmbus: add a helper function to set a channel's pending send size This will be used by the coming net/hvsock driver. @@ -32,5 +32,5 @@ index ae6a711..fda6310 100644 int vmbus_request_offers(void); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0016-Drivers-hv-vmbus-define-the-new-offer-type-for-Hyper.patch b/alpine/kernel/patches/0016-Drivers-hv-vmbus-define-the-new-offer-type-for-Hyper.patch index 6375840e7..05c6c2b6f 100644 --- a/alpine/kernel/patches/0016-Drivers-hv-vmbus-define-the-new-offer-type-for-Hyper.patch +++ b/alpine/kernel/patches/0016-Drivers-hv-vmbus-define-the-new-offer-type-for-Hyper.patch @@ -1,7 +1,7 @@ -From 7d695c9e75755b005a7f45f99dfd7d3bb641e3a8 Mon Sep 17 00:00:00 2001 +From 14c27d35657e10990f6b428460ef9d5fc81ffca4 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:38 -0800 -Subject: [PATCH 16/26] Drivers: hv: vmbus: define the new offer type for +Subject: [PATCH 16/27] Drivers: hv: vmbus: define the new offer type for Hyper-V socket (hvsock) A helper function is also added. @@ -40,5 +40,5 @@ index fda6310..9fb2130 100644 enum hv_signal_policy policy) { -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0017-Drivers-hv-vmbus-vmbus_sendpacket_ctl-hvsock-avoid-u.patch b/alpine/kernel/patches/0017-Drivers-hv-vmbus-vmbus_sendpacket_ctl-hvsock-avoid-u.patch index 0bafa0231..229220b5c 100644 --- a/alpine/kernel/patches/0017-Drivers-hv-vmbus-vmbus_sendpacket_ctl-hvsock-avoid-u.patch +++ b/alpine/kernel/patches/0017-Drivers-hv-vmbus-vmbus_sendpacket_ctl-hvsock-avoid-u.patch @@ -1,7 +1,7 @@ -From 8507cfd5b7af092d5cc5e99ff9852b3bc46c48c0 Mon Sep 17 00:00:00 2001 +From ff94799688f8090c70cdca2158a8c0ca7a9f676c Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:39 -0800 -Subject: [PATCH 17/26] Drivers: hv: vmbus: vmbus_sendpacket_ctl: hvsock: avoid +Subject: [PATCH 17/27] Drivers: hv: vmbus: vmbus_sendpacket_ctl: hvsock: avoid unnecessary signaling When the hvsock channel's outbound ringbuffer is full (i.e., @@ -41,5 +41,5 @@ index 2889d97..a7f9e3e 100644 return ret; -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0018-Drivers-hv-vmbus-define-a-new-VMBus-message-type-for.patch b/alpine/kernel/patches/0018-Drivers-hv-vmbus-define-a-new-VMBus-message-type-for.patch index 3745823ac..a60cb43f7 100644 --- a/alpine/kernel/patches/0018-Drivers-hv-vmbus-define-a-new-VMBus-message-type-for.patch +++ b/alpine/kernel/patches/0018-Drivers-hv-vmbus-define-a-new-VMBus-message-type-for.patch @@ -1,7 +1,7 @@ -From 746cdb5f4c824ef3af9d12909818a077a0cf303c Mon Sep 17 00:00:00 2001 +From 91c41d9e85f67881be5523d544508c08ca9926e3 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:40 -0800 -Subject: [PATCH 18/26] Drivers: hv: vmbus: define a new VMBus message type for +Subject: [PATCH 18/27] Drivers: hv: vmbus: define a new VMBus message type for hvsock A function to send the type of message is also added. @@ -97,5 +97,5 @@ index 9fb2130..3f485a4 100644 + const uuid_le *shv_host_servie_id); #endif /* _HYPERV_H */ -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0019-Drivers-hv-vmbus-add-a-hvsock-flag-in-struct-hv_driv.patch b/alpine/kernel/patches/0019-Drivers-hv-vmbus-add-a-hvsock-flag-in-struct-hv_driv.patch index 919219600..57236bb02 100644 --- a/alpine/kernel/patches/0019-Drivers-hv-vmbus-add-a-hvsock-flag-in-struct-hv_driv.patch +++ b/alpine/kernel/patches/0019-Drivers-hv-vmbus-add-a-hvsock-flag-in-struct-hv_driv.patch @@ -1,7 +1,7 @@ -From fb6b14a429dae008b7fee772a1e27cb09db459b7 Mon Sep 17 00:00:00 2001 +From 22631e9eff59670c7cef5f91979375a2144189dd Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:41 -0800 -Subject: [PATCH 19/26] Drivers: hv: vmbus: add a hvsock flag in struct +Subject: [PATCH 19/27] Drivers: hv: vmbus: add a hvsock flag in struct hv_driver Only the coming hv_sock driver has a "true" value for this flag. @@ -60,5 +60,5 @@ index 3f485a4..9ee79af 100644 uuid_le dev_type; const struct hv_vmbus_device_id *id_table; -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0020-Drivers-hv-vmbus-add-a-per-channel-rescind-callback.patch b/alpine/kernel/patches/0020-Drivers-hv-vmbus-add-a-per-channel-rescind-callback.patch index 4db143cad..02d193f90 100644 --- a/alpine/kernel/patches/0020-Drivers-hv-vmbus-add-a-per-channel-rescind-callback.patch +++ b/alpine/kernel/patches/0020-Drivers-hv-vmbus-add-a-per-channel-rescind-callback.patch @@ -1,7 +1,7 @@ -From 4a2d55757c137c2e574500227cb2efe77a26ee3a Mon Sep 17 00:00:00 2001 +From 220aa4002752a3ce9d8b7a8010c64d8a9c3e1654 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:42 -0800 -Subject: [PATCH 20/26] Drivers: hv: vmbus: add a per-channel rescind callback +Subject: [PATCH 20/27] Drivers: hv: vmbus: add a per-channel rescind callback This will be used by the coming hv_sock driver. @@ -68,5 +68,5 @@ index 9ee79af..09e9ec1 100644 * Retrieve the (sub) channel on which to send an outgoing request. * When a primary channel has multiple sub-channels, we choose a -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0021-Drivers-hv-vmbus-add-an-API-vmbus_hvsock_device_unre.patch b/alpine/kernel/patches/0021-Drivers-hv-vmbus-add-an-API-vmbus_hvsock_device_unre.patch index f22acd28b..f03bb8787 100644 --- a/alpine/kernel/patches/0021-Drivers-hv-vmbus-add-an-API-vmbus_hvsock_device_unre.patch +++ b/alpine/kernel/patches/0021-Drivers-hv-vmbus-add-an-API-vmbus_hvsock_device_unre.patch @@ -1,7 +1,7 @@ -From b6c9f23164d3e7460d8983d27f2df194ab5e9a0b Mon Sep 17 00:00:00 2001 +From 8cdace7efd0cba254c7183e302d97e2018d61840 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 27 Jan 2016 22:29:43 -0800 -Subject: [PATCH 21/26] Drivers: hv: vmbus: add an API +Subject: [PATCH 21/27] Drivers: hv: vmbus: add an API vmbus_hvsock_device_unregister() The hvsock driver needs this API to release all the resources related @@ -149,5 +149,5 @@ index 09e9ec1..af7ee0a 100644 resource_size_t min, resource_size_t max, resource_size_t size, resource_size_t align, -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0022-kcm-Kernel-Connection-Multiplexor-module.patch b/alpine/kernel/patches/0022-kcm-Kernel-Connection-Multiplexor-module.patch index f2180adca..8abab54e9 100644 --- a/alpine/kernel/patches/0022-kcm-Kernel-Connection-Multiplexor-module.patch +++ b/alpine/kernel/patches/0022-kcm-Kernel-Connection-Multiplexor-module.patch @@ -1,7 +1,7 @@ -From f483aa8ef1890f82d6a362d296c21786c5ee9f30 Mon Sep 17 00:00:00 2001 +From d2dabcfdbf46a4c78f87d1a6b56822a3ed10499a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 7 Mar 2016 14:11:06 -0800 -Subject: [PATCH 22/26] kcm: Kernel Connection Multiplexor module +Subject: [PATCH 22/27] kcm: Kernel Connection Multiplexor module This module implements the Kernel Connection Multiplexor. @@ -18,13 +18,13 @@ Signed-off-by: David S. Miller --- include/linux/socket.h | 6 +- include/net/kcm.h | 125 +++ - include/uapi/linux/kcm.h | 40 + + include/uapi/linux/kcm.h | 39 + net/Kconfig | 1 + net/Makefile | 1 + - net/kcm/Kconfig | 10 + + net/kcm/Kconfig | 9 + net/kcm/Makefile | 3 + - net/kcm/kcmsock.c | 2016 ++++++++++++++++++++++++++++++++++++++++++++++ - 8 files changed, 2201 insertions(+), 1 deletion(-) + net/kcm/kcmsock.c | 2015 ++++++++++++++++++++++++++++++++++++++++++++++ + 8 files changed, 2198 insertions(+), 1 deletion(-) create mode 100644 include/net/kcm.h create mode 100644 include/uapi/linux/kcm.h create mode 100644 net/kcm/Kconfig @@ -195,10 +195,10 @@ index 0000000..1bcae39 +#endif /* __NET_KCM_H_ */ diff --git a/include/uapi/linux/kcm.h b/include/uapi/linux/kcm.h new file mode 100644 -index 0000000..a5a53094 +index 0000000..d72350f --- /dev/null +++ b/include/uapi/linux/kcm.h -@@ -0,0 +1,40 @@ +@@ -0,0 +1,39 @@ +/* + * Kernel Connection Multiplexor + * @@ -238,7 +238,6 @@ index 0000000..a5a53094 +#define KCM_RECV_DISABLE 1 + +#endif -+ diff --git a/net/Kconfig b/net/Kconfig index 127da94..b8439e6 100644 --- a/net/Kconfig @@ -265,10 +264,10 @@ index a5d0409..81d1411 100644 obj-$(CONFIG_DECNET) += decnet/ diff --git a/net/kcm/Kconfig b/net/kcm/Kconfig new file mode 100644 -index 0000000..5db94d9 +index 0000000..4f28332 --- /dev/null +++ b/net/kcm/Kconfig -@@ -0,0 +1,10 @@ +@@ -0,0 +1,9 @@ + +config AF_KCM + tristate "KCM sockets" @@ -278,7 +277,6 @@ index 0000000..5db94d9 + KCM (Kernel Connection Multiplexor) sockets provide a method + for multiplexing messages of a message based application + protocol over kernel connectons (e.g. TCP connections). -+ diff --git a/net/kcm/Makefile b/net/kcm/Makefile new file mode 100644 index 0000000..cb525f7 @@ -290,10 +288,10 @@ index 0000000..cb525f7 +kcm-y := kcmsock.o diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c new file mode 100644 -index 0000000..30ef69a +index 0000000..649d246 --- /dev/null +++ b/net/kcm/kcmsock.c -@@ -0,0 +1,2016 @@ +@@ -0,0 +1,2015 @@ +#include +#include +#include @@ -2309,7 +2307,6 @@ index 0000000..30ef69a + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_KCM); -+ -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0023-net-add-the-AF_KCM-entries-to-family-name-tables.patch b/alpine/kernel/patches/0023-net-add-the-AF_KCM-entries-to-family-name-tables.patch index 98c89d268..06a3b1834 100644 --- a/alpine/kernel/patches/0023-net-add-the-AF_KCM-entries-to-family-name-tables.patch +++ b/alpine/kernel/patches/0023-net-add-the-AF_KCM-entries-to-family-name-tables.patch @@ -1,7 +1,7 @@ -From 4e7679280dd0ad8e28f9ebeea70127ed4385222a Mon Sep 17 00:00:00 2001 +From 5df30f620de871e80745c25687dbcb5af4c532e5 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 21 Mar 2016 02:51:09 -0700 -Subject: [PATCH 23/26] net: add the AF_KCM entries to family name tables +Subject: [PATCH 23/27] net: add the AF_KCM entries to family name tables This is for the recent kcm driver, which introduces AF_KCM(41) in b7ac4eb(kcm: Kernel Connection Multiplexor module). @@ -48,5 +48,5 @@ index 0d91f7d..925def4 100644 /* -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0024-net-Add-Qualcomm-IPC-router.patch b/alpine/kernel/patches/0024-net-Add-Qualcomm-IPC-router.patch new file mode 100644 index 000000000..cd0dac24b --- /dev/null +++ b/alpine/kernel/patches/0024-net-Add-Qualcomm-IPC-router.patch @@ -0,0 +1,1307 @@ +From daaab04e678f6e0b64de7d12ac87183ae6581a3e Mon Sep 17 00:00:00 2001 +From: Courtney Cavin +Date: Wed, 27 Apr 2016 12:13:03 -0700 +Subject: [PATCH 24/27] net: Add Qualcomm IPC router + +Add an implementation of Qualcomm's IPC router protocol, used to +communicate with service providing remote processors. + +Signed-off-by: Courtney Cavin +Signed-off-by: Bjorn Andersson +[bjorn: Cope with 0 being a valid node id and implement RTM_NEWADDR] +Signed-off-by: Bjorn Andersson +Origin: https://patchwork.ozlabs.org/patch/615774/ +--- + include/linux/socket.h | 4 +- + include/uapi/linux/qrtr.h | 12 + + net/Kconfig | 1 + + net/Makefile | 1 + + net/qrtr/Kconfig | 24 ++ + net/qrtr/Makefile | 2 + + net/qrtr/qrtr.c | 1007 +++++++++++++++++++++++++++++++++++++++++++++ + net/qrtr/qrtr.h | 31 ++ + net/qrtr/smd.c | 117 ++++++ + 9 files changed, 1198 insertions(+), 1 deletion(-) + create mode 100644 include/uapi/linux/qrtr.h + create mode 100644 net/qrtr/Kconfig + create mode 100644 net/qrtr/Makefile + create mode 100644 net/qrtr/qrtr.c + create mode 100644 net/qrtr/qrtr.h + create mode 100644 net/qrtr/smd.c + +diff --git a/include/linux/socket.h b/include/linux/socket.h +index 4e1ea53..dbd81e7 100644 +--- a/include/linux/socket.h ++++ b/include/linux/socket.h +@@ -201,8 +201,9 @@ struct ucred { + #define AF_NFC 39 /* NFC sockets */ + #define AF_VSOCK 40 /* vSockets */ + #define AF_KCM 41 /* Kernel Connection Multiplexor*/ ++#define AF_QIPCRTR 42 /* Qualcomm IPC Router */ + +-#define AF_MAX 42 /* For now.. */ ++#define AF_MAX 43 /* For now.. */ + + /* Protocol families, same as address families. */ + #define PF_UNSPEC AF_UNSPEC +@@ -249,6 +250,7 @@ struct ucred { + #define PF_NFC AF_NFC + #define PF_VSOCK AF_VSOCK + #define PF_KCM AF_KCM ++#define PF_QIPCRTR AF_QIPCRTR + #define PF_MAX AF_MAX + + /* Maximum queue length specifiable by listen. */ +diff --git a/include/uapi/linux/qrtr.h b/include/uapi/linux/qrtr.h +new file mode 100644 +index 0000000..66c0748 +--- /dev/null ++++ b/include/uapi/linux/qrtr.h +@@ -0,0 +1,12 @@ ++#ifndef _LINUX_QRTR_H ++#define _LINUX_QRTR_H ++ ++#include ++ ++struct sockaddr_qrtr { ++ __kernel_sa_family_t sq_family; ++ __u32 sq_node; ++ __u32 sq_port; ++}; ++ ++#endif /* _LINUX_QRTR_H */ +diff --git a/net/Kconfig b/net/Kconfig +index b8439e6..1c9fda1 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -233,6 +233,7 @@ source "net/mpls/Kconfig" + source "net/hsr/Kconfig" + source "net/switchdev/Kconfig" + source "net/l3mdev/Kconfig" ++source "net/qrtr/Kconfig" + + config RPS + bool +diff --git a/net/Makefile b/net/Makefile +index 81d1411..bdd1455 100644 +--- a/net/Makefile ++++ b/net/Makefile +@@ -78,3 +78,4 @@ endif + ifneq ($(CONFIG_NET_L3_MASTER_DEV),) + obj-y += l3mdev/ + endif ++obj-$(CONFIG_QRTR) += qrtr/ +diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig +new file mode 100644 +index 0000000..0c2619d +--- /dev/null ++++ b/net/qrtr/Kconfig +@@ -0,0 +1,24 @@ ++# Qualcomm IPC Router configuration ++# ++ ++config QRTR ++ bool "Qualcomm IPC Router support" ++ depends on ARCH_QCOM || COMPILE_TEST ++ ---help--- ++ Say Y if you intend to use Qualcomm IPC router protocol. The ++ protocol is used to communicate with services provided by other ++ hardware blocks in the system. ++ ++ In order to do service lookups, a userspace daemon is required to ++ maintain a service listing. ++ ++if QRTR ++ ++config QRTR_SMD ++ tristate "SMD IPC Router channels" ++ depends on QCOM_SMD || COMPILE_TEST ++ ---help--- ++ Say Y here to support SMD based ipcrouter channels. SMD is the ++ most common transport for IPC Router. ++ ++endif # QRTR +diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile +new file mode 100644 +index 0000000..e282a84 +--- /dev/null ++++ b/net/qrtr/Makefile +@@ -0,0 +1,2 @@ ++obj-y := qrtr.o ++obj-$(CONFIG_QRTR_SMD) += smd.o +diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c +new file mode 100644 +index 0000000..c985ecb +--- /dev/null ++++ b/net/qrtr/qrtr.c +@@ -0,0 +1,1007 @@ ++/* ++ * Copyright (c) 2015, Sony Mobile Communications Inc. ++ * Copyright (c) 2013, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include ++#include ++#include ++#include /* For TIOCINQ/OUTQ */ ++ ++#include ++ ++#include "qrtr.h" ++ ++#define QRTR_PROTO_VER 1 ++ ++/* auto-bind range */ ++#define QRTR_MIN_EPH_SOCKET 0x4000 ++#define QRTR_MAX_EPH_SOCKET 0x7fff ++ ++enum qrtr_pkt_type { ++ QRTR_TYPE_DATA = 1, ++ QRTR_TYPE_HELLO = 2, ++ QRTR_TYPE_BYE = 3, ++ QRTR_TYPE_NEW_SERVER = 4, ++ QRTR_TYPE_DEL_SERVER = 5, ++ QRTR_TYPE_DEL_CLIENT = 6, ++ QRTR_TYPE_RESUME_TX = 7, ++ QRTR_TYPE_EXIT = 8, ++ QRTR_TYPE_PING = 9, ++}; ++ ++/** ++ * struct qrtr_hdr - (I|R)PCrouter packet header ++ * @version: protocol version ++ * @type: packet type; one of QRTR_TYPE_* ++ * @src_node_id: source node ++ * @src_port_id: source port ++ * @confirm_rx: boolean; whether a resume-tx packet should be send in reply ++ * @size: length of packet, excluding this header ++ * @dst_node_id: destination node ++ * @dst_port_id: destination port ++ */ ++struct qrtr_hdr { ++ __le32 version; ++ __le32 type; ++ __le32 src_node_id; ++ __le32 src_port_id; ++ __le32 confirm_rx; ++ __le32 size; ++ __le32 dst_node_id; ++ __le32 dst_port_id; ++} __packed; ++ ++#define QRTR_HDR_SIZE sizeof(struct qrtr_hdr) ++#define QRTR_NODE_BCAST ((unsigned int)-1) ++#define QRTR_PORT_CTRL ((unsigned int)-2) ++ ++struct qrtr_sock { ++ /* WARNING: sk must be the first member */ ++ struct sock sk; ++ struct sockaddr_qrtr us; ++ struct sockaddr_qrtr peer; ++}; ++ ++static inline struct qrtr_sock *qrtr_sk(struct sock *sk) ++{ ++ BUILD_BUG_ON(offsetof(struct qrtr_sock, sk) != 0); ++ return container_of(sk, struct qrtr_sock, sk); ++} ++ ++static unsigned int qrtr_local_nid = -1; ++ ++/* for node ids */ ++static RADIX_TREE(qrtr_nodes, GFP_KERNEL); ++/* broadcast list */ ++static LIST_HEAD(qrtr_all_nodes); ++/* lock for qrtr_nodes, qrtr_all_nodes and node reference */ ++static DEFINE_MUTEX(qrtr_node_lock); ++ ++/* local port allocation management */ ++static DEFINE_IDR(qrtr_ports); ++static DEFINE_MUTEX(qrtr_port_lock); ++ ++/** ++ * struct qrtr_node - endpoint node ++ * @ep_lock: lock for endpoint management and callbacks ++ * @ep: endpoint ++ * @ref: reference count for node ++ * @nid: node id ++ * @rx_queue: receive queue ++ * @work: scheduled work struct for recv work ++ * @item: list item for broadcast list ++ */ ++struct qrtr_node { ++ struct mutex ep_lock; ++ struct qrtr_endpoint *ep; ++ struct kref ref; ++ unsigned int nid; ++ ++ struct sk_buff_head rx_queue; ++ struct work_struct work; ++ struct list_head item; ++}; ++ ++/* Release node resources and free the node. ++ * ++ * Do not call directly, use qrtr_node_release. To be used with ++ * kref_put_mutex. As such, the node mutex is expected to be locked on call. ++ */ ++static void __qrtr_node_release(struct kref *kref) ++{ ++ struct qrtr_node *node = container_of(kref, struct qrtr_node, ref); ++ ++ if (node->nid != QRTR_EP_NID_AUTO) ++ radix_tree_delete(&qrtr_nodes, node->nid); ++ ++ list_del(&node->item); ++ mutex_unlock(&qrtr_node_lock); ++ ++ skb_queue_purge(&node->rx_queue); ++ kfree(node); ++} ++ ++/* Increment reference to node. */ ++static struct qrtr_node *qrtr_node_acquire(struct qrtr_node *node) ++{ ++ if (node) ++ kref_get(&node->ref); ++ return node; ++} ++ ++/* Decrement reference to node and release as necessary. */ ++static void qrtr_node_release(struct qrtr_node *node) ++{ ++ if (!node) ++ return; ++ kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock); ++} ++ ++/* Pass an outgoing packet socket buffer to the endpoint driver. */ ++static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb) ++{ ++ int rc = -ENODEV; ++ ++ mutex_lock(&node->ep_lock); ++ if (node->ep) ++ rc = node->ep->xmit(node->ep, skb); ++ else ++ kfree_skb(skb); ++ mutex_unlock(&node->ep_lock); ++ ++ return rc; ++} ++ ++/* Lookup node by id. ++ * ++ * callers must release with qrtr_node_release() ++ */ ++static struct qrtr_node *qrtr_node_lookup(unsigned int nid) ++{ ++ struct qrtr_node *node; ++ ++ mutex_lock(&qrtr_node_lock); ++ node = radix_tree_lookup(&qrtr_nodes, nid); ++ node = qrtr_node_acquire(node); ++ mutex_unlock(&qrtr_node_lock); ++ ++ return node; ++} ++ ++/* Assign node id to node. ++ * ++ * This is mostly useful for automatic node id assignment, based on ++ * the source id in the incoming packet. ++ */ ++static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) ++{ ++ if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO) ++ return; ++ ++ mutex_lock(&qrtr_node_lock); ++ radix_tree_insert(&qrtr_nodes, nid, node); ++ node->nid = nid; ++ mutex_unlock(&qrtr_node_lock); ++} ++ ++/** ++ * qrtr_endpoint_post() - post incoming data ++ * @ep: endpoint handle ++ * @data: data pointer ++ * @len: size of data in bytes ++ * ++ * Return: 0 on success; negative error code on failure ++ */ ++int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) ++{ ++ struct qrtr_node *node = ep->node; ++ const struct qrtr_hdr *phdr = data; ++ struct sk_buff *skb; ++ unsigned int psize; ++ unsigned int size; ++ unsigned int type; ++ unsigned int ver; ++ unsigned int dst; ++ ++ if (len < QRTR_HDR_SIZE || len & 3) ++ return -EINVAL; ++ ++ ver = le32_to_cpu(phdr->version); ++ size = le32_to_cpu(phdr->size); ++ type = le32_to_cpu(phdr->type); ++ dst = le32_to_cpu(phdr->dst_port_id); ++ ++ psize = (size + 3) & ~3; ++ ++ if (ver != QRTR_PROTO_VER) ++ return -EINVAL; ++ ++ if (len != psize + QRTR_HDR_SIZE) ++ return -EINVAL; ++ ++ if (dst != QRTR_PORT_CTRL && type != QRTR_TYPE_DATA) ++ return -EINVAL; ++ ++ skb = netdev_alloc_skb(NULL, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ skb_reset_transport_header(skb); ++ memcpy(skb_put(skb, len), data, len); ++ ++ skb_queue_tail(&node->rx_queue, skb); ++ schedule_work(&node->work); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(qrtr_endpoint_post); ++ ++/* Allocate and construct a resume-tx packet. */ ++static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node, ++ u32 dst_node, u32 port) ++{ ++ const int pkt_len = 20; ++ struct qrtr_hdr *hdr; ++ struct sk_buff *skb; ++ u32 *buf; ++ ++ skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL); ++ if (!skb) ++ return NULL; ++ skb_reset_transport_header(skb); ++ ++ hdr = (struct qrtr_hdr *)skb_put(skb, QRTR_HDR_SIZE); ++ hdr->version = cpu_to_le32(QRTR_PROTO_VER); ++ hdr->type = cpu_to_le32(QRTR_TYPE_RESUME_TX); ++ hdr->src_node_id = cpu_to_le32(src_node); ++ hdr->src_port_id = cpu_to_le32(QRTR_PORT_CTRL); ++ hdr->confirm_rx = cpu_to_le32(0); ++ hdr->size = cpu_to_le32(pkt_len); ++ hdr->dst_node_id = cpu_to_le32(dst_node); ++ hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL); ++ ++ buf = (u32 *)skb_put(skb, pkt_len); ++ memset(buf, 0, pkt_len); ++ buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX); ++ buf[1] = cpu_to_le32(src_node); ++ buf[2] = cpu_to_le32(port); ++ ++ return skb; ++} ++ ++static struct qrtr_sock *qrtr_port_lookup(int port); ++static void qrtr_port_put(struct qrtr_sock *ipc); ++ ++/* Handle and route a received packet. ++ * ++ * This will auto-reply with resume-tx packet as necessary. ++ */ ++static void qrtr_node_rx_work(struct work_struct *work) ++{ ++ struct qrtr_node *node = container_of(work, struct qrtr_node, work); ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&node->rx_queue)) != NULL) { ++ const struct qrtr_hdr *phdr; ++ u32 dst_node, dst_port; ++ struct qrtr_sock *ipc; ++ u32 src_node; ++ int confirm; ++ ++ phdr = (const struct qrtr_hdr *)skb_transport_header(skb); ++ src_node = le32_to_cpu(phdr->src_node_id); ++ dst_node = le32_to_cpu(phdr->dst_node_id); ++ dst_port = le32_to_cpu(phdr->dst_port_id); ++ confirm = !!phdr->confirm_rx; ++ ++ qrtr_node_assign(node, src_node); ++ ++ ipc = qrtr_port_lookup(dst_port); ++ if (!ipc) { ++ kfree_skb(skb); ++ } else { ++ if (sock_queue_rcv_skb(&ipc->sk, skb)) ++ kfree_skb(skb); ++ ++ qrtr_port_put(ipc); ++ } ++ ++ if (confirm) { ++ skb = qrtr_alloc_resume_tx(dst_node, node->nid, dst_port); ++ if (!skb) ++ break; ++ if (qrtr_node_enqueue(node, skb)) ++ break; ++ } ++ } ++} ++ ++/** ++ * qrtr_endpoint_register() - register a new endpoint ++ * @ep: endpoint to register ++ * @nid: desired node id; may be QRTR_EP_NID_AUTO for auto-assignment ++ * Return: 0 on success; negative error code on failure ++ * ++ * The specified endpoint must have the xmit function pointer set on call. ++ */ ++int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) ++{ ++ struct qrtr_node *node; ++ ++ if (!ep || !ep->xmit) ++ return -EINVAL; ++ ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (!node) ++ return -ENOMEM; ++ ++ INIT_WORK(&node->work, qrtr_node_rx_work); ++ kref_init(&node->ref); ++ mutex_init(&node->ep_lock); ++ skb_queue_head_init(&node->rx_queue); ++ node->nid = QRTR_EP_NID_AUTO; ++ node->ep = ep; ++ ++ qrtr_node_assign(node, nid); ++ ++ mutex_lock(&qrtr_node_lock); ++ list_add(&node->item, &qrtr_all_nodes); ++ mutex_unlock(&qrtr_node_lock); ++ ep->node = node; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(qrtr_endpoint_register); ++ ++/** ++ * qrtr_endpoint_unregister - unregister endpoint ++ * @ep: endpoint to unregister ++ */ ++void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) ++{ ++ struct qrtr_node *node = ep->node; ++ ++ mutex_lock(&node->ep_lock); ++ node->ep = NULL; ++ mutex_unlock(&node->ep_lock); ++ ++ qrtr_node_release(node); ++ ep->node = NULL; ++} ++EXPORT_SYMBOL_GPL(qrtr_endpoint_unregister); ++ ++/* Lookup socket by port. ++ * ++ * Callers must release with qrtr_port_put() ++ */ ++static struct qrtr_sock *qrtr_port_lookup(int port) ++{ ++ struct qrtr_sock *ipc; ++ ++ if (port == QRTR_PORT_CTRL) ++ port = 0; ++ ++ mutex_lock(&qrtr_port_lock); ++ ipc = idr_find(&qrtr_ports, port); ++ if (ipc) ++ sock_hold(&ipc->sk); ++ mutex_unlock(&qrtr_port_lock); ++ ++ return ipc; ++} ++ ++/* Release acquired socket. */ ++static void qrtr_port_put(struct qrtr_sock *ipc) ++{ ++ sock_put(&ipc->sk); ++} ++ ++/* Remove port assignment. */ ++static void qrtr_port_remove(struct qrtr_sock *ipc) ++{ ++ int port = ipc->us.sq_port; ++ ++ if (port == QRTR_PORT_CTRL) ++ port = 0; ++ ++ __sock_put(&ipc->sk); ++ ++ mutex_lock(&qrtr_port_lock); ++ idr_remove(&qrtr_ports, port); ++ mutex_unlock(&qrtr_port_lock); ++} ++ ++/* Assign port number to socket. ++ * ++ * Specify port in the integer pointed to by port, and it will be adjusted ++ * on return as necesssary. ++ * ++ * Port may be: ++ * 0: Assign ephemeral port in [QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET] ++ * QRTR_MIN_EPH_SOCKET: Specified; available to all ++ */ ++static int qrtr_port_assign(struct qrtr_sock *ipc, int *port) ++{ ++ int rc; ++ ++ mutex_lock(&qrtr_port_lock); ++ if (!*port) { ++ rc = idr_alloc(&qrtr_ports, ipc, ++ QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET + 1, ++ GFP_ATOMIC); ++ if (rc >= 0) ++ *port = rc; ++ } else if (*port < QRTR_MIN_EPH_SOCKET && !capable(CAP_NET_ADMIN)) { ++ rc = -EACCES; ++ } else if (*port == QRTR_PORT_CTRL) { ++ rc = idr_alloc(&qrtr_ports, ipc, 0, 1, GFP_ATOMIC); ++ } else { ++ rc = idr_alloc(&qrtr_ports, ipc, *port, *port + 1, GFP_ATOMIC); ++ if (rc >= 0) ++ *port = rc; ++ } ++ mutex_unlock(&qrtr_port_lock); ++ ++ if (rc == -ENOSPC) ++ return -EADDRINUSE; ++ else if (rc < 0) ++ return rc; ++ ++ sock_hold(&ipc->sk); ++ ++ return 0; ++} ++ ++/* Bind socket to address. ++ * ++ * Socket should be locked upon call. ++ */ ++static int __qrtr_bind(struct socket *sock, ++ const struct sockaddr_qrtr *addr, int zapped) ++{ ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sock *sk = sock->sk; ++ int port; ++ int rc; ++ ++ /* rebinding ok */ ++ if (!zapped && addr->sq_port == ipc->us.sq_port) ++ return 0; ++ ++ port = addr->sq_port; ++ rc = qrtr_port_assign(ipc, &port); ++ if (rc) ++ return rc; ++ ++ /* unbind previous, if any */ ++ if (!zapped) ++ qrtr_port_remove(ipc); ++ ipc->us.sq_port = port; ++ ++ sock_reset_flag(sk, SOCK_ZAPPED); ++ ++ return 0; ++} ++ ++/* Auto bind to an ephemeral port. */ ++static int qrtr_autobind(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ struct sockaddr_qrtr addr; ++ ++ if (!sock_flag(sk, SOCK_ZAPPED)) ++ return 0; ++ ++ addr.sq_family = AF_QIPCRTR; ++ addr.sq_node = qrtr_local_nid; ++ addr.sq_port = 0; ++ ++ return __qrtr_bind(sock, &addr, 1); ++} ++ ++/* Bind socket to specified sockaddr. */ ++static int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len) ++{ ++ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr); ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sock *sk = sock->sk; ++ int rc; ++ ++ if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR) ++ return -EINVAL; ++ ++ if (addr->sq_node != ipc->us.sq_node) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ rc = __qrtr_bind(sock, addr, sock_flag(sk, SOCK_ZAPPED)); ++ release_sock(sk); ++ ++ return rc; ++} ++ ++/* Queue packet to local peer socket. */ ++static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb) ++{ ++ const struct qrtr_hdr *phdr; ++ struct qrtr_sock *ipc; ++ ++ phdr = (const struct qrtr_hdr *)skb_transport_header(skb); ++ ++ ipc = qrtr_port_lookup(le32_to_cpu(phdr->dst_port_id)); ++ if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */ ++ kfree_skb(skb); ++ return -ENODEV; ++ } ++ ++ if (sock_queue_rcv_skb(&ipc->sk, skb)) { ++ qrtr_port_put(ipc); ++ kfree_skb(skb); ++ return -ENOSPC; ++ } ++ ++ qrtr_port_put(ipc); ++ ++ return 0; ++} ++ ++/* Queue packet for broadcast. */ ++static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb) ++{ ++ struct sk_buff *skbn; ++ ++ mutex_lock(&qrtr_node_lock); ++ list_for_each_entry(node, &qrtr_all_nodes, item) { ++ skbn = skb_clone(skb, GFP_KERNEL); ++ if (!skbn) ++ break; ++ skb_set_owner_w(skbn, skb->sk); ++ qrtr_node_enqueue(node, skbn); ++ } ++ mutex_unlock(&qrtr_node_lock); ++ ++ qrtr_local_enqueue(node, skb); ++ ++ return 0; ++} ++ ++static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ++{ ++ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name); ++ int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *); ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sock *sk = sock->sk; ++ struct qrtr_node *node; ++ struct qrtr_hdr *hdr; ++ struct sk_buff *skb; ++ size_t plen; ++ int rc; ++ ++ if (msg->msg_flags & ~(MSG_DONTWAIT)) ++ return -EINVAL; ++ ++ if (len > 65535) ++ return -EMSGSIZE; ++ ++ lock_sock(sk); ++ ++ if (addr) { ++ if (msg->msg_namelen < sizeof(*addr)) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ ++ if (addr->sq_family != AF_QIPCRTR) { ++ release_sock(sk); ++ return -EINVAL; ++ } ++ ++ rc = qrtr_autobind(sock); ++ if (rc) { ++ release_sock(sk); ++ return rc; ++ } ++ } else if (sk->sk_state == TCP_ESTABLISHED) { ++ addr = &ipc->peer; ++ } else { ++ release_sock(sk); ++ return -ENOTCONN; ++ } ++ ++ node = NULL; ++ if (addr->sq_node == QRTR_NODE_BCAST) { ++ enqueue_fn = qrtr_bcast_enqueue; ++ } else if (addr->sq_node == ipc->us.sq_node) { ++ enqueue_fn = qrtr_local_enqueue; ++ } else { ++ enqueue_fn = qrtr_node_enqueue; ++ node = qrtr_node_lookup(addr->sq_node); ++ if (!node) { ++ release_sock(sk); ++ return -ECONNRESET; ++ } ++ } ++ ++ plen = (len + 3) & ~3; ++ skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_SIZE, ++ msg->msg_flags & MSG_DONTWAIT, &rc); ++ if (!skb) ++ goto out_node; ++ ++ skb_reset_transport_header(skb); ++ skb_put(skb, len + QRTR_HDR_SIZE); ++ ++ hdr = (struct qrtr_hdr *)skb_transport_header(skb); ++ hdr->version = cpu_to_le32(QRTR_PROTO_VER); ++ hdr->src_node_id = cpu_to_le32(ipc->us.sq_node); ++ hdr->src_port_id = cpu_to_le32(ipc->us.sq_port); ++ hdr->confirm_rx = cpu_to_le32(0); ++ hdr->size = cpu_to_le32(len); ++ hdr->dst_node_id = cpu_to_le32(addr->sq_node); ++ hdr->dst_port_id = cpu_to_le32(addr->sq_port); ++ ++ rc = skb_copy_datagram_from_iter(skb, QRTR_HDR_SIZE, ++ &msg->msg_iter, len); ++ if (rc) { ++ kfree_skb(skb); ++ goto out_node; ++ } ++ ++ if (plen != len) { ++ skb_pad(skb, plen - len); ++ skb_put(skb, plen - len); ++ } ++ ++ if (ipc->us.sq_port == QRTR_PORT_CTRL) { ++ if (len < 4) { ++ rc = -EINVAL; ++ kfree_skb(skb); ++ goto out_node; ++ } ++ ++ /* control messages already require the type as 'command' */ ++ skb_copy_bits(skb, QRTR_HDR_SIZE, &hdr->type, 4); ++ } else { ++ hdr->type = cpu_to_le32(QRTR_TYPE_DATA); ++ } ++ ++ rc = enqueue_fn(node, skb); ++ if (rc >= 0) ++ rc = len; ++ ++out_node: ++ qrtr_node_release(node); ++ release_sock(sk); ++ ++ return rc; ++} ++ ++static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg, ++ size_t size, int flags) ++{ ++ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name); ++ const struct qrtr_hdr *phdr; ++ struct sock *sk = sock->sk; ++ struct sk_buff *skb; ++ int copied, rc; ++ ++ lock_sock(sk); ++ ++ if (sock_flag(sk, SOCK_ZAPPED)) { ++ release_sock(sk); ++ return -EADDRNOTAVAIL; ++ } ++ ++ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, ++ flags & MSG_DONTWAIT, &rc); ++ if (!skb) { ++ release_sock(sk); ++ return rc; ++ } ++ ++ phdr = (const struct qrtr_hdr *)skb_transport_header(skb); ++ copied = le32_to_cpu(phdr->size); ++ if (copied > size) { ++ copied = size; ++ msg->msg_flags |= MSG_TRUNC; ++ } ++ ++ rc = skb_copy_datagram_msg(skb, QRTR_HDR_SIZE, msg, copied); ++ if (rc < 0) ++ goto out; ++ rc = copied; ++ ++ if (addr) { ++ addr->sq_family = AF_QIPCRTR; ++ addr->sq_node = le32_to_cpu(phdr->src_node_id); ++ addr->sq_port = le32_to_cpu(phdr->src_port_id); ++ msg->msg_namelen = sizeof(*addr); ++ } ++ ++out: ++ skb_free_datagram(sk, skb); ++ release_sock(sk); ++ ++ return rc; ++} ++ ++static int qrtr_connect(struct socket *sock, struct sockaddr *saddr, ++ int len, int flags) ++{ ++ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr); ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sock *sk = sock->sk; ++ int rc; ++ ++ if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ sk->sk_state = TCP_CLOSE; ++ sock->state = SS_UNCONNECTED; ++ ++ rc = qrtr_autobind(sock); ++ if (rc) { ++ release_sock(sk); ++ return rc; ++ } ++ ++ ipc->peer = *addr; ++ sock->state = SS_CONNECTED; ++ sk->sk_state = TCP_ESTABLISHED; ++ ++ release_sock(sk); ++ ++ return 0; ++} ++ ++static int qrtr_getname(struct socket *sock, struct sockaddr *saddr, ++ int *len, int peer) ++{ ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sockaddr_qrtr qaddr; ++ struct sock *sk = sock->sk; ++ ++ lock_sock(sk); ++ if (peer) { ++ if (sk->sk_state != TCP_ESTABLISHED) { ++ release_sock(sk); ++ return -ENOTCONN; ++ } ++ ++ qaddr = ipc->peer; ++ } else { ++ qaddr = ipc->us; ++ } ++ release_sock(sk); ++ ++ *len = sizeof(qaddr); ++ qaddr.sq_family = AF_QIPCRTR; ++ ++ memcpy(saddr, &qaddr, sizeof(qaddr)); ++ ++ return 0; ++} ++ ++static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ struct qrtr_sock *ipc = qrtr_sk(sock->sk); ++ struct sock *sk = sock->sk; ++ struct sockaddr_qrtr *sq; ++ struct sk_buff *skb; ++ struct ifreq ifr; ++ long len = 0; ++ int rc = 0; ++ ++ lock_sock(sk); ++ ++ switch (cmd) { ++ case TIOCOUTQ: ++ len = sk->sk_sndbuf - sk_wmem_alloc_get(sk); ++ if (len < 0) ++ len = 0; ++ rc = put_user(len, (int __user *)argp); ++ break; ++ case TIOCINQ: ++ skb = skb_peek(&sk->sk_receive_queue); ++ if (skb) ++ len = skb->len - QRTR_HDR_SIZE; ++ rc = put_user(len, (int __user *)argp); ++ break; ++ case SIOCGIFADDR: ++ if (copy_from_user(&ifr, argp, sizeof(ifr))) { ++ rc = -EFAULT; ++ break; ++ } ++ ++ sq = (struct sockaddr_qrtr *)&ifr.ifr_addr; ++ *sq = ipc->us; ++ if (copy_to_user(argp, &ifr, sizeof(ifr))) { ++ rc = -EFAULT; ++ break; ++ } ++ break; ++ case SIOCGSTAMP: ++ rc = sock_get_timestamp(sk, argp); ++ break; ++ case SIOCADDRT: ++ case SIOCDELRT: ++ case SIOCSIFADDR: ++ case SIOCGIFDSTADDR: ++ case SIOCSIFDSTADDR: ++ case SIOCGIFBRDADDR: ++ case SIOCSIFBRDADDR: ++ case SIOCGIFNETMASK: ++ case SIOCSIFNETMASK: ++ rc = -EINVAL; ++ break; ++ default: ++ rc = -ENOIOCTLCMD; ++ break; ++ } ++ ++ release_sock(sk); ++ ++ return rc; ++} ++ ++static int qrtr_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ struct qrtr_sock *ipc; ++ ++ if (!sk) ++ return 0; ++ ++ lock_sock(sk); ++ ++ ipc = qrtr_sk(sk); ++ sk->sk_shutdown = SHUTDOWN_MASK; ++ if (!sock_flag(sk, SOCK_DEAD)) ++ sk->sk_state_change(sk); ++ ++ sock_set_flag(sk, SOCK_DEAD); ++ sock->sk = NULL; ++ ++ if (!sock_flag(sk, SOCK_ZAPPED)) ++ qrtr_port_remove(ipc); ++ ++ skb_queue_purge(&sk->sk_receive_queue); ++ ++ release_sock(sk); ++ sock_put(sk); ++ ++ return 0; ++} ++ ++static const struct proto_ops qrtr_proto_ops = { ++ .owner = THIS_MODULE, ++ .family = AF_QIPCRTR, ++ .bind = qrtr_bind, ++ .connect = qrtr_connect, ++ .socketpair = sock_no_socketpair, ++ .accept = sock_no_accept, ++ .listen = sock_no_listen, ++ .sendmsg = qrtr_sendmsg, ++ .recvmsg = qrtr_recvmsg, ++ .getname = qrtr_getname, ++ .ioctl = qrtr_ioctl, ++ .poll = datagram_poll, ++ .shutdown = sock_no_shutdown, ++ .setsockopt = sock_no_setsockopt, ++ .getsockopt = sock_no_getsockopt, ++ .release = qrtr_release, ++ .mmap = sock_no_mmap, ++ .sendpage = sock_no_sendpage, ++}; ++ ++static struct proto qrtr_proto = { ++ .name = "QIPCRTR", ++ .owner = THIS_MODULE, ++ .obj_size = sizeof(struct qrtr_sock), ++}; ++ ++static int qrtr_create(struct net *net, struct socket *sock, ++ int protocol, int kern) ++{ ++ struct qrtr_sock *ipc; ++ struct sock *sk; ++ ++ if (sock->type != SOCK_DGRAM) ++ return -EPROTOTYPE; ++ ++ sk = sk_alloc(net, AF_QIPCRTR, GFP_KERNEL, &qrtr_proto, kern); ++ if (!sk) ++ return -ENOMEM; ++ ++ sock_set_flag(sk, SOCK_ZAPPED); ++ ++ sock_init_data(sock, sk); ++ sock->ops = &qrtr_proto_ops; ++ ++ ipc = qrtr_sk(sk); ++ ipc->us.sq_family = AF_QIPCRTR; ++ ipc->us.sq_node = qrtr_local_nid; ++ ipc->us.sq_port = 0; ++ ++ return 0; ++} ++ ++static const struct nla_policy qrtr_policy[IFA_MAX + 1] = { ++ [IFA_LOCAL] = { .type = NLA_U32 }, ++}; ++ ++static int qrtr_addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh) ++{ ++ struct nlattr *tb[IFA_MAX + 1]; ++ struct ifaddrmsg *ifm; ++ int rc; ++ ++ if (!netlink_capable(skb, CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (!netlink_capable(skb, CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ ASSERT_RTNL(); ++ ++ rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, qrtr_policy); ++ if (rc < 0) ++ return rc; ++ ++ ifm = nlmsg_data(nlh); ++ if (!tb[IFA_LOCAL]) ++ return -EINVAL; ++ ++ qrtr_local_nid = nla_get_u32(tb[IFA_LOCAL]); ++ return 0; ++} ++ ++static const struct net_proto_family qrtr_family = { ++ .owner = THIS_MODULE, ++ .family = AF_QIPCRTR, ++ .create = qrtr_create, ++}; ++ ++static int __init qrtr_proto_init(void) ++{ ++ int rc; ++ ++ rc = proto_register(&qrtr_proto, 1); ++ if (rc) ++ return rc; ++ ++ rc = sock_register(&qrtr_family); ++ if (rc) { ++ proto_unregister(&qrtr_proto); ++ return rc; ++ } ++ ++ rtnl_register(PF_QIPCRTR, RTM_NEWADDR, qrtr_addr_doit, NULL, NULL); ++ ++ return 0; ++} ++module_init(qrtr_proto_init); ++ ++static void __exit qrtr_proto_fini(void) ++{ ++ rtnl_unregister(PF_QIPCRTR, RTM_NEWADDR); ++ sock_unregister(qrtr_family.family); ++ proto_unregister(&qrtr_proto); ++} ++module_exit(qrtr_proto_fini); ++ ++MODULE_DESCRIPTION("Qualcomm IPC-router driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h +new file mode 100644 +index 0000000..2b84871 +--- /dev/null ++++ b/net/qrtr/qrtr.h +@@ -0,0 +1,31 @@ ++#ifndef __QRTR_H_ ++#define __QRTR_H_ ++ ++#include ++ ++struct sk_buff; ++ ++/* endpoint node id auto assignment */ ++#define QRTR_EP_NID_AUTO (-1) ++ ++/** ++ * struct qrtr_endpoint - endpoint handle ++ * @xmit: Callback for outgoing packets ++ * ++ * The socket buffer passed to the xmit function becomes owned by the endpoint ++ * driver. As such, when the driver is done with the buffer, it should ++ * call kfree_skb() on failure, or consume_skb() on success. ++ */ ++struct qrtr_endpoint { ++ int (*xmit)(struct qrtr_endpoint *ep, struct sk_buff *skb); ++ /* private: not for endpoint use */ ++ struct qrtr_node *node; ++}; ++ ++int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid); ++ ++void qrtr_endpoint_unregister(struct qrtr_endpoint *ep); ++ ++int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len); ++ ++#endif +diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c +new file mode 100644 +index 0000000..84ebce7 +--- /dev/null ++++ b/net/qrtr/smd.c +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2015, Sony Mobile Communications Inc. ++ * Copyright (c) 2013, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++#include "qrtr.h" ++ ++struct qrtr_smd_dev { ++ struct qrtr_endpoint ep; ++ struct qcom_smd_channel *channel; ++}; ++ ++/* from smd to qrtr */ ++static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev, ++ const void *data, size_t len) ++{ ++ struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev); ++ int rc; ++ ++ if (!qdev) ++ return -EAGAIN; ++ ++ rc = qrtr_endpoint_post(&qdev->ep, data, len); ++ if (rc == -EINVAL) { ++ dev_err(&sdev->dev, "invalid ipcrouter packet\n"); ++ /* return 0 to let smd drop the packet */ ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++/* from qrtr to smd */ ++static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) ++{ ++ struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep); ++ int rc; ++ ++ rc = skb_linearize(skb); ++ if (rc) ++ goto out; ++ ++ rc = qcom_smd_send(qdev->channel, skb->data, skb->len); ++ ++out: ++ if (rc) ++ kfree_skb(skb); ++ else ++ consume_skb(skb); ++ return rc; ++} ++ ++static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev) ++{ ++ struct qrtr_smd_dev *qdev; ++ int rc; ++ ++ qdev = devm_kzalloc(&sdev->dev, sizeof(*qdev), GFP_KERNEL); ++ if (!qdev) ++ return -ENOMEM; ++ ++ qdev->channel = sdev->channel; ++ qdev->ep.xmit = qcom_smd_qrtr_send; ++ ++ rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); ++ if (rc) ++ return rc; ++ ++ dev_set_drvdata(&sdev->dev, qdev); ++ ++ dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n"); ++ ++ return 0; ++} ++ ++static void qcom_smd_qrtr_remove(struct qcom_smd_device *sdev) ++{ ++ struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev); ++ ++ qrtr_endpoint_unregister(&qdev->ep); ++ ++ dev_set_drvdata(&sdev->dev, NULL); ++} ++ ++static const struct qcom_smd_id qcom_smd_qrtr_smd_match[] = { ++ { "IPCRTR" }, ++ {} ++}; ++ ++static struct qcom_smd_driver qcom_smd_qrtr_driver = { ++ .probe = qcom_smd_qrtr_probe, ++ .remove = qcom_smd_qrtr_remove, ++ .callback = qcom_smd_qrtr_callback, ++ .smd_match_table = qcom_smd_qrtr_smd_match, ++ .driver = { ++ .name = "qcom_smd_qrtr", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_qcom_smd_driver(qcom_smd_qrtr_driver); ++ ++MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.8.2 + diff --git a/alpine/kernel/patches/0024-hv_sock-introduce-Hyper-V-Sockets.patch b/alpine/kernel/patches/0025-hv_sock-introduce-Hyper-V-Sockets.patch similarity index 78% rename from alpine/kernel/patches/0024-hv_sock-introduce-Hyper-V-Sockets.patch rename to alpine/kernel/patches/0025-hv_sock-introduce-Hyper-V-Sockets.patch index b2dd4ce33..6dbf04400 100644 --- a/alpine/kernel/patches/0024-hv_sock-introduce-Hyper-V-Sockets.patch +++ b/alpine/kernel/patches/0025-hv_sock-introduce-Hyper-V-Sockets.patch @@ -1,7 +1,7 @@ -From 65ca3b4d64bbe02b726a91e837605c6d082fb9b9 Mon Sep 17 00:00:00 2001 +From 20eefd65c0ddcc93c8de196ee4d21b3dacc24c37 Mon Sep 17 00:00:00 2001 From: Dexuan Cui -Date: Mon, 21 Mar 2016 02:52:49 -0700 -Subject: [PATCH 24/26] hv_sock: introduce Hyper-V Sockets +Date: Wed, 11 May 2016 10:52:37 -0700 +Subject: [PATCH 25/27] hv_sock: introduce Hyper-V Sockets Hyper-V Sockets (hv_sock) supplies a byte-stream based communication mechanism between the host and the guest. It's somewhat like TCP over @@ -21,29 +21,30 @@ Signed-off-by: Dexuan Cui Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Cc: Vitaly Kuznetsov -Origin: https://patchwork.ozlabs.org/patch/600008 +Cc: Cathy Avery +Origin: http://patchwork.ozlabs.org/patch/621190/ --- MAINTAINERS | 2 + - include/linux/hyperv.h | 16 + - include/linux/socket.h | 5 +- - include/net/af_hvsock.h | 51 ++ - include/uapi/linux/hyperv.h | 16 + + include/linux/hyperv.h | 14 + + include/linux/socket.h | 4 +- + include/net/af_hvsock.h | 78 +++ + include/uapi/linux/hyperv.h | 25 + net/Kconfig | 1 + net/Makefile | 1 + net/hv_sock/Kconfig | 10 + net/hv_sock/Makefile | 3 + - net/hv_sock/af_hvsock.c | 1480 +++++++++++++++++++++++++++++++++++++++++++ - 10 files changed, 1583 insertions(+), 2 deletions(-) + net/hv_sock/af_hvsock.c | 1484 +++++++++++++++++++++++++++++++++++++++++++ + 10 files changed, 1621 insertions(+), 1 deletion(-) create mode 100644 include/net/af_hvsock.h create mode 100644 net/hv_sock/Kconfig create mode 100644 net/hv_sock/Makefile create mode 100644 net/hv_sock/af_hvsock.c diff --git a/MAINTAINERS b/MAINTAINERS -index 530bce8..3af3740 100644 +index 9a70d2d..1021706 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -5136,7 +5136,9 @@ F: drivers/input/serio/hyperv-keyboard.c +@@ -5123,7 +5123,9 @@ F: drivers/input/serio/hyperv-keyboard.c F: drivers/net/hyperv/ F: drivers/scsi/storvsc_drv.c F: drivers/video/fbdev/hyperv_fb.c @@ -54,17 +55,17 @@ index 530bce8..3af3740 100644 F: Documentation/ABI/stable/sysfs-bus-vmbus diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h -index af7ee0a..b78205e 100644 +index af7ee0a..9864a30 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h -@@ -1314,4 +1314,20 @@ extern __u32 vmbus_proto_version; +@@ -1314,4 +1314,18 @@ extern __u32 vmbus_proto_version; int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id, const uuid_le *shv_host_servie_id); +struct vmpipe_proto_header { + u32 pkt_type; + u32 data_size; -+} __packed; ++}; + +#define HVSOCK_HEADER_LEN (sizeof(struct vmpacket_descriptor) + \ + sizeof(struct vmpipe_proto_header)) @@ -75,38 +76,36 @@ index af7ee0a..b78205e 100644 +#define HVSOCK_PKT_LEN(payload_len) (HVSOCK_HEADER_LEN + \ + ALIGN((payload_len), 8) + \ + PREV_INDICES_LEN) -+#define HVSOCK_MIN_PKT_LEN HVSOCK_PKT_LEN(1) -+ #endif /* _HYPERV_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h -index 4e1ea53..2a28c5f 100644 +index dbd81e7..6634c47 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h -@@ -201,8 +201,8 @@ struct ucred { - #define AF_NFC 39 /* NFC sockets */ +@@ -202,8 +202,9 @@ struct ucred { #define AF_VSOCK 40 /* vSockets */ #define AF_KCM 41 /* Kernel Connection Multiplexor*/ -- --#define AF_MAX 42 /* For now.. */ -+#define AF_HYPERV 42 /* Hyper-V Sockets */ -+#define AF_MAX 43 /* For now.. */ + #define AF_QIPCRTR 42 /* Qualcomm IPC Router */ ++#define AF_HYPERV 43 /* Hyper-V Sockets */ + +-#define AF_MAX 43 /* For now.. */ ++#define AF_MAX 44 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC -@@ -249,6 +249,7 @@ struct ucred { - #define PF_NFC AF_NFC +@@ -251,6 +252,7 @@ struct ucred { #define PF_VSOCK AF_VSOCK #define PF_KCM AF_KCM + #define PF_QIPCRTR AF_QIPCRTR +#define PF_HYPERV AF_HYPERV #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/include/net/af_hvsock.h b/include/net/af_hvsock.h new file mode 100644 -index 0000000..a5aa28d +index 0000000..e002397 --- /dev/null +++ b/include/net/af_hvsock.h -@@ -0,0 +1,51 @@ +@@ -0,0 +1,78 @@ +#ifndef __AF_HVSOCK_H__ +#define __AF_HVSOCK_H__ + @@ -114,14 +113,50 @@ index 0000000..a5aa28d +#include +#include + -+#define VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV (5 * PAGE_SIZE) -+#define VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND (5 * PAGE_SIZE) ++/* Note: 3-page is the minimal recv ringbuffer size: ++ * ++ * the 1st page is used as the shared read/write index etc, rather than data: ++ * see hv_ringbuffer_init(); ++ * ++ * the payload length in the vmbus pipe message received from the host can ++ * be 4096 bytes, and considing the header of HVSOCK_HEADER_LEN bytes, we ++ * need at least 2 extra pages for ringbuffer data. ++ */ ++#define HVSOCK_RCV_BUF_SZ PAGE_SIZE ++#define VMBUS_RINGBUFFER_SIZE_HVSOCK_RCV (3 * PAGE_SIZE) + -+#define HVSOCK_RCV_BUF_SZ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV -+#define HVSOCK_SND_BUF_SZ PAGE_SIZE ++/* As to send, here let's make sure the hvsock_send_buf struct can be held in 1 ++ * page, and since we want to use 2 pages for the send ringbuffer size (this is ++ * the minimal size because the 1st page of the two is used as the shared ++ * read/write index etc, rather than data), we only have 1 page for ringbuffer ++ * data, this means: the max payload length for hvsock data is ++ * PAGE_SIZE - HVSOCK_PKT_LEN(0). Finally, let's reduce the length by 8-bytes ++ * because the ringbuffer can't be 100% full: see hv_ringbuffer_write(). ++ */ ++#define HVSOCK_SND_BUF_SZ (PAGE_SIZE - HVSOCK_PKT_LEN(0) - 8) ++#define VMBUS_RINGBUFFER_SIZE_HVSOCK_SND (2 * PAGE_SIZE) + -+#define sk_to_hvsock(__sk) ((struct hvsock_sock *)(__sk)) -+#define hvsock_to_sk(__hvsk) ((struct sock *)(__hvsk)) ++/* We only send data when the available space is "big enough". This artificial ++ * value must be less than HVSOCK_SND_BUF_SZ. ++ * ++ */ ++#define HVSOCK_SND_THRESHOLD (PAGE_SIZE / 2) ++ ++#define sk_to_hvsock(__sk) ((struct hvsock_sock *)(__sk)) ++#define hvsock_to_sk(__hvsk) ((struct sock *)(__hvsk)) ++ ++struct hvsock_send_buf { ++ struct vmpipe_proto_header hdr; ++ u8 buf[HVSOCK_SND_BUF_SZ]; ++}; ++ ++struct hvsock_recv_buf { ++ struct vmpipe_proto_header hdr; ++ u8 buf[HVSOCK_RCV_BUF_SZ]; ++ ++ unsigned int data_len; ++ unsigned int data_offset; ++}; + +struct hvsock_sock { + /* sk must be the first member. */ @@ -144,22 +179,13 @@ index 0000000..a5aa28d + + struct vmbus_channel *channel; + -+ struct { -+ struct vmpipe_proto_header hdr; -+ char buf[HVSOCK_SND_BUF_SZ]; -+ } __packed send; -+ -+ struct { -+ struct vmpipe_proto_header hdr; -+ char buf[HVSOCK_RCV_BUF_SZ]; -+ unsigned int data_len; -+ unsigned int data_offset; -+ } __packed recv; ++ struct hvsock_send_buf *send; ++ struct hvsock_recv_buf *recv; +}; + +#endif /* __AF_HVSOCK_H__ */ diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h -index e4c0a35..18ca18a 100644 +index e4c0a35..9a698c1 100644 --- a/include/uapi/linux/hyperv.h +++ b/include/uapi/linux/hyperv.h @@ -26,6 +26,7 @@ @@ -170,16 +196,25 @@ index e4c0a35..18ca18a 100644 /* * Framework version for util services. -@@ -395,4 +396,19 @@ struct hv_kvp_ip_msg { +@@ -395,4 +396,28 @@ struct hv_kvp_ip_msg { struct hv_kvp_ipaddr_value kvp_ip_val; } __attribute__((packed)); -+/* This is the Hyper-V socket's address format. */ ++/* ++ * This is the address fromat of Hyper-V Sockets. ++ * Note: here we just borrow the kernel's built-in type uuid_le. When ++ * an application calls bind() or connect(), the 2 members of struct ++ * sockaddr_hv must be of GUID. ++ * The GUID format differs from the UUID format only in the byte order of ++ * the first 3 fields. Refer to: ++ * https://en.wikipedia.org/wiki/Globally_unique_identifier ++ */ ++#define guid_t uuid_le +struct sockaddr_hv { + __kernel_sa_family_t shv_family; /* Address family */ + __le16 reserved; /* Must be Zero */ -+ uuid_le shv_vm_id; /* Not used. Must be Zero. */ -+ uuid_le shv_service_id; /* Service ID */ ++ guid_t shv_vm_id; /* VM ID */ ++ guid_t shv_service_id; /* Service ID */ +}; + +#define SHV_VMID_GUEST NULL_UUID_LE @@ -191,7 +226,7 @@ index e4c0a35..18ca18a 100644 + #endif /* _UAPI_HYPERV_H */ diff --git a/net/Kconfig b/net/Kconfig -index b8439e6..ebc8f20 100644 +index 1c9fda1..9eeccb7 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -228,6 +228,7 @@ source "net/dns_resolver/Kconfig" @@ -203,7 +238,7 @@ index b8439e6..ebc8f20 100644 source "net/mpls/Kconfig" source "net/hsr/Kconfig" diff --git a/net/Makefile b/net/Makefile -index 81d1411..d115c31 100644 +index bdd1455..ec175dd 100644 --- a/net/Makefile +++ b/net/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv/ @@ -241,12 +276,13 @@ index 0000000..716c012 +hv_sock-y += af_hvsock.o diff --git a/net/hv_sock/af_hvsock.c b/net/hv_sock/af_hvsock.c new file mode 100644 -index 0000000..e5639eb +index 0000000..013d684 --- /dev/null +++ b/net/hv_sock/af_hvsock.c -@@ -0,0 +1,1480 @@ +@@ -0,0 +1,1484 @@ +/* -+ * Hyper-V Socket driver ++ * Hyper-V Sockets -- a socket-based communication channel between the ++ * Hyper-V host and the virtual machines running on it. + * + * Copyright(c) 2016, Microsoft Corporation. All rights reserved. + * @@ -298,72 +334,30 @@ index 0000000..e5639eb + return !uuid_le_cmp(u1, u2); +} + -+/* NOTE: hvsock_mutex must be held when the below helper functions, whose -+ * names begin with __ hvsock, are invoked. -+ */ -+static void __hvsock_insert_bound(struct list_head *list, -+ struct hvsock_sock *hvsk) -+{ -+ sock_hold(&hvsk->sk); -+ list_add(&hvsk->bound_list, list); -+} -+ -+static void __hvsock_insert_connected(struct list_head *list, -+ struct hvsock_sock *hvsk) -+{ -+ sock_hold(&hvsk->sk); -+ list_add(&hvsk->connected_list, list); -+} -+ -+static void __hvsock_remove_bound(struct hvsock_sock *hvsk) -+{ -+ list_del_init(&hvsk->bound_list); -+ sock_put(&hvsk->sk); -+} -+ -+static void __hvsock_remove_connected(struct hvsock_sock *hvsk) -+{ -+ list_del_init(&hvsk->connected_list); -+ sock_put(&hvsk->sk); -+} -+ -+static struct sock *__hvsock_find_bound_socket(const struct sockaddr_hv *addr) ++static struct sock *hvsock_find_bound_socket(const struct sockaddr_hv *addr) +{ + struct hvsock_sock *hvsk; + -+ list_for_each_entry(hvsk, &hvsock_bound_list, bound_list) ++ list_for_each_entry(hvsk, &hvsock_bound_list, bound_list) { + if (uuid_equals(addr->shv_service_id, + hvsk->local_addr.shv_service_id)) + return hvsock_to_sk(hvsk); ++ } + return NULL; +} + -+static struct sock *__hvsock_find_connected_socket_by_channel( ++static struct sock *hvsock_find_connected_socket_by_channel( + const struct vmbus_channel *channel) +{ + struct hvsock_sock *hvsk; + -+ list_for_each_entry(hvsk, &hvsock_connected_list, connected_list) ++ list_for_each_entry(hvsk, &hvsock_connected_list, connected_list) { + if (hvsk->channel == channel) + return hvsock_to_sk(hvsk); ++ } + return NULL; +} + -+static bool __hvsock_in_bound_list(struct hvsock_sock *hvsk) -+{ -+ return !list_empty(&hvsk->bound_list); -+} -+ -+static bool __hvsock_in_connected_list(struct hvsock_sock *hvsk) -+{ -+ return !list_empty(&hvsk->connected_list); -+} -+ -+static void hvsock_insert_connected(struct hvsock_sock *hvsk) -+{ -+ __hvsock_insert_connected(&hvsock_connected_list, hvsk); -+} -+ +static +void hvsock_enqueue_accept(struct sock *listener, struct sock *connected) +{ @@ -442,9 +436,6 @@ index 0000000..e5639eb + if (addr->reserved != 0) + return -EINVAL; + -+ if (!uuid_equals(addr->shv_vm_id, NULL_UUID_LE)) -+ return -EINVAL; -+ + return 0; +} + @@ -476,17 +467,18 @@ index 0000000..e5639eb + if (uuid_equals(addr->shv_service_id, SHV_SERVICE_ID_ANY)) { + do { + uuid_le_gen(&hv_addr.shv_service_id); -+ } while (__hvsock_find_bound_socket(&hv_addr)); ++ } while (hvsock_find_bound_socket(&hv_addr)); + } else { -+ if (__hvsock_find_bound_socket(&hv_addr)) { ++ if (hvsock_find_bound_socket(&hv_addr)) { + ret = -EADDRINUSE; + goto out; + } + } + + hvsock_addr_init(&hvsk->local_addr, hv_addr.shv_service_id); -+ __hvsock_insert_bound(&hvsock_bound_list, hvsk); + ++ sock_hold(&hvsk->sk); ++ list_add(&hvsk->bound_list, &hvsock_bound_list); +out: + mutex_unlock(&hvsock_mutex); + @@ -531,6 +523,9 @@ index 0000000..e5639eb + struct hvsock_sock *hvsk = sk_to_hvsock(sk); + struct vmbus_channel *channel = hvsk->channel; + ++ kfree(hvsk->send); ++ kfree(hvsk->recv); ++ + if (!channel) + return; + @@ -545,11 +540,17 @@ index 0000000..e5639eb + hvsk = sk_to_hvsock(sk); + + mutex_lock(&hvsock_mutex); -+ if (__hvsock_in_bound_list(hvsk)) -+ __hvsock_remove_bound(hvsk); + -+ if (__hvsock_in_connected_list(hvsk)) -+ __hvsock_remove_connected(hvsk); ++ if (!list_empty(&hvsk->bound_list)) { ++ list_del_init(&hvsk->bound_list); ++ sock_put(&hvsk->sk); ++ } ++ ++ if (!list_empty(&hvsk->connected_list)) { ++ list_del_init(&hvsk->connected_list); ++ sock_put(&hvsk->sk); ++ } ++ + mutex_unlock(&hvsock_mutex); + + lock_sock(sk); @@ -583,12 +584,20 @@ index 0000000..e5639eb +static struct sock *__hvsock_create(struct net *net, struct socket *sock, + gfp_t priority, unsigned short type) +{ ++ struct hvsock_send_buf *send = NULL; ++ struct hvsock_recv_buf *recv = NULL; ++ + struct hvsock_sock *hvsk; + struct sock *sk; + ++ send = kmalloc(sizeof(struct hvsock_send_buf), GFP_KERNEL); ++ recv = kmalloc(sizeof(struct hvsock_recv_buf), GFP_KERNEL); ++ if (!send || !recv) ++ goto err; ++ + sk = sk_alloc(net, AF_HYPERV, priority, &hvsock_proto, 0); + if (!sk) -+ return NULL; ++ goto err; + + sock_init_data(sock, sk); + @@ -599,9 +608,6 @@ index 0000000..e5639eb + if (!sock) + sk->sk_type = type; + -+ hvsk = sk_to_hvsock(sk); -+ hvsock_addr_init(&hvsk->local_addr, SHV_SERVICE_ID_ANY); -+ hvsock_addr_init(&hvsk->remote_addr, SHV_SERVICE_ID_ANY); + + sk->sk_destruct = hvsock_sk_destruct; + @@ -611,6 +617,14 @@ index 0000000..e5639eb + sk->sk_state = 0; + sock_reset_flag(sk, SOCK_DONE); + ++ hvsk = sk_to_hvsock(sk); ++ ++ hvsk->send = send; ++ hvsk->recv = recv; ++ ++ hvsock_addr_init(&hvsk->local_addr, SHV_SERVICE_ID_ANY); ++ hvsock_addr_init(&hvsk->remote_addr, SHV_SERVICE_ID_ANY); ++ + INIT_LIST_HEAD(&hvsk->bound_list); + INIT_LIST_HEAD(&hvsk->connected_list); + @@ -619,10 +633,14 @@ index 0000000..e5639eb + + hvsk->peer_shutdown = 0; + -+ hvsk->recv.data_len = 0; -+ hvsk->recv.data_offset = 0; ++ hvsk->recv->data_len = 0; ++ hvsk->recv->data_offset = 0; + + return sk; ++err: ++ kfree(send); ++ kfree(recv); ++ return NULL; +} + +static int hvsock_bind(struct socket *sock, struct sockaddr *addr, @@ -637,6 +655,9 @@ index 0000000..e5639eb + if (hvsock_addr_cast(addr, addr_len, &hv_addr) != 0) + return -EINVAL; + ++ if (!uuid_equals(hv_addr->shv_vm_id, NULL_UUID_LE)) ++ return -EINVAL; ++ + lock_sock(sk); + ret = __hvsock_bind(sk, hv_addr); + release_sock(sk); @@ -721,21 +742,37 @@ index 0000000..e5639eb + hv_get_ringbuffer_availbytes(&channel->inbound, + &avl_read_bytes, + &dummy); -+ *can_read = avl_read_bytes >= HVSOCK_MIN_PKT_LEN; ++ /* 0-size payload meaans FIN */ ++ *can_read = avl_read_bytes >= HVSOCK_PKT_LEN(0); + } + -+ /* We write into the ringbuffer only when we're able to write a -+ * a payload of 4096 bytes (the actual written payload's length may be -+ * less than 4096). -+ */ + if (can_write) { + hv_get_ringbuffer_availbytes(&channel->outbound, + &dummy, + &avl_write_bytes); -+ *can_write = avl_write_bytes > HVSOCK_PKT_LEN(PAGE_SIZE); ++ ++ *can_write = avl_write_bytes > ++ HVSOCK_PKT_LEN(HVSOCK_SND_THRESHOLD); + } +} + ++static size_t get_ringbuffer_writable_bytes(struct vmbus_channel *channel) ++{ ++ u32 avl_write_bytes, dummy; ++ size_t ret; ++ ++ hv_get_ringbuffer_availbytes(&channel->outbound, ++ &dummy, ++ &avl_write_bytes); ++ ++ if (avl_write_bytes < HVSOCK_PKT_LEN(1)) ++ return 0; ++ ++ /* The ringbuffer can't be 100% full */ ++ ret = avl_write_bytes - HVSOCK_PKT_LEN(1); ++ return round_down(ret, 8); ++} ++ +static unsigned int hvsock_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ @@ -785,7 +822,7 @@ index 0000000..e5639eb + /* If there is something in the queue then we can read */ + get_ringbuffer_rw_status(channel, &can_read, &can_write); + -+ if (!can_read && hvsk->recv.data_len > 0) ++ if (!can_read && hvsk->recv->data_len > 0) + can_read = true; + + if (!(sk->sk_shutdown & RCV_SHUTDOWN) && can_read) @@ -855,7 +892,7 @@ index 0000000..e5639eb + + mutex_lock(&hvsock_mutex); + -+ sk = __hvsock_find_connected_socket_by_channel(channel); ++ sk = hvsock_find_connected_socket_by_channel(channel); + + /* The guest has already closed the connection? */ + if (!sk) @@ -878,6 +915,7 @@ index 0000000..e5639eb + struct hvsock_sock *hvsk, *new_hvsk; + struct sockaddr_hv hv_addr; + struct sock *sk, *new_sk; ++ unsigned char conn_from_host; + + uuid_le *instance, *service_id; + int ret; @@ -885,83 +923,75 @@ index 0000000..e5639eb + instance = &channel->offermsg.offer.if_instance; + service_id = &channel->offermsg.offer.if_type; + -+ hvsock_addr_init(&hv_addr, *instance); ++ /* The first byte != 0 means the host initiated the connection. */ ++ conn_from_host = channel->offermsg.offer.u.pipe.user_def[0]; + + mutex_lock(&hvsock_mutex); + -+ sk = __hvsock_find_bound_socket(&hv_addr); ++ hvsock_addr_init(&hv_addr, conn_from_host ? *service_id : *instance); ++ sk = hvsock_find_bound_socket(&hv_addr); + -+ if (sk) { -+ /* It is from the guest client's connect() */ -+ if (sk->sk_state != SS_CONNECTING) { -+ ret = -ENXIO; -+ goto out; -+ } -+ -+ hvsk = sk_to_hvsock(sk); -+ hvsk->channel = channel; -+ set_channel_read_state(channel, false); -+ vmbus_set_chn_rescind_callback(channel, -+ hvsock_close_connection); -+ ret = vmbus_open(channel, VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND, -+ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV, NULL, 0, -+ hvsock_on_channel_cb, sk); -+ if (ret != 0) { -+ hvsk->channel = NULL; -+ goto out; -+ } -+ -+ set_channel_pending_send_size(channel, -+ HVSOCK_PKT_LEN(PAGE_SIZE)); -+ sk->sk_state = SS_CONNECTED; -+ sk->sk_socket->state = SS_CONNECTED; -+ hvsock_insert_connected(hvsk); -+ sk->sk_state_change(sk); -+ goto out; -+ } -+ -+ /* Now we suppose it is from a host client's connect() */ -+ hvsock_addr_init(&hv_addr, *service_id); -+ sk = __hvsock_find_bound_socket(&hv_addr); -+ -+ /* No guest server listening? Well, let's ignore the offer */ -+ if (!sk || sk->sk_state != SS_LISTEN) { ++ if (!sk || (conn_from_host && sk->sk_state != SS_LISTEN) || ++ (!conn_from_host && sk->sk_state != SS_CONNECTING)) { + ret = -ENXIO; + goto out; + } + -+ if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) { -+ ret = -EMFILE; -+ goto out; -+ } ++ if (conn_from_host) { ++ if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) { ++ ret = -EMFILE; ++ goto out; ++ } + -+ new_sk = __hvsock_create(sock_net(sk), NULL, GFP_KERNEL, sk->sk_type); -+ if (!new_sk) { -+ ret = -ENOMEM; -+ goto out; ++ new_sk = __hvsock_create(sock_net(sk), NULL, GFP_KERNEL, ++ sk->sk_type); ++ if (!new_sk) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ new_sk->sk_state = SS_CONNECTING; ++ new_hvsk = sk_to_hvsock(new_sk); ++ new_hvsk->channel = channel; ++ hvsock_addr_init(&new_hvsk->local_addr, *service_id); ++ hvsock_addr_init(&new_hvsk->remote_addr, *instance); ++ } else { ++ hvsk = sk_to_hvsock(sk); ++ hvsk->channel = channel; + } + -+ new_hvsk = sk_to_hvsock(new_sk); -+ new_sk->sk_state = SS_CONNECTING; -+ hvsock_addr_init(&new_hvsk->local_addr, *service_id); -+ hvsock_addr_init(&new_hvsk->remote_addr, *instance); -+ + set_channel_read_state(channel, false); -+ new_hvsk->channel = channel; + vmbus_set_chn_rescind_callback(channel, hvsock_close_connection); -+ ret = vmbus_open(channel, VMBUS_RINGBUFFER_SIZE_HVSOCK_SEND, -+ VMBUS_RINGBUFFER_SIZE_HVSOCK_RECV, NULL, 0, -+ hvsock_on_channel_cb, new_sk); ++ ret = vmbus_open(channel, VMBUS_RINGBUFFER_SIZE_HVSOCK_SND, ++ VMBUS_RINGBUFFER_SIZE_HVSOCK_RCV, NULL, 0, ++ hvsock_on_channel_cb, conn_from_host ? new_sk : sk); + if (ret != 0) { -+ new_hvsk->channel = NULL; -+ sock_put(new_sk); ++ if (conn_from_host) { ++ new_hvsk->channel = NULL; ++ sock_put(new_sk); ++ } else { ++ hvsk->channel = NULL; ++ } + goto out; + } -+ set_channel_pending_send_size(channel, HVSOCK_PKT_LEN(PAGE_SIZE)); + -+ new_sk->sk_state = SS_CONNECTED; -+ hvsock_insert_connected(new_hvsk); -+ hvsock_enqueue_accept(sk, new_sk); ++ set_channel_pending_send_size(channel, ++ HVSOCK_PKT_LEN(HVSOCK_SND_THRESHOLD)); ++ ++ if (conn_from_host) { ++ new_sk->sk_state = SS_CONNECTED; ++ ++ sock_hold(&new_hvsk->sk); ++ list_add(&new_hvsk->connected_list, &hvsock_connected_list); ++ ++ hvsock_enqueue_accept(sk, new_sk); ++ } else { ++ sk->sk_state = SS_CONNECTED; ++ sk->sk_socket->state = SS_CONNECTED; ++ ++ sock_hold(&hvsk->sk); ++ list_add(&hvsk->connected_list, &hvsock_connected_list); ++ } ++ + sk->sk_state_change(sk); +out: + mutex_unlock(&hvsock_mutex); @@ -988,16 +1018,69 @@ index 0000000..e5639eb + sock_put(sk); +} + ++static int hvsock_connect_wait(struct socket *sock, ++ int flags, int current_ret) ++{ ++ struct sock *sk = sock->sk; ++ struct hvsock_sock *hvsk = sk_to_hvsock(sk); ++ ++ int ret = current_ret; ++ ++ long timeout = 30 * HZ; ++ DEFINE_WAIT(wait); ++ ++ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); ++ ++ while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) { ++ if (flags & O_NONBLOCK) { ++ /* If we're not going to block, we schedule a timeout ++ * function to generate a timeout on the connection ++ * attempt, in case the peer doesn't respond in a ++ * timely manner. We hold on to the socket until the ++ * timeout fires. ++ */ ++ sock_hold(sk); ++ INIT_DELAYED_WORK(&hvsk->dwork, ++ hvsock_connect_timeout); ++ schedule_delayed_work(&hvsk->dwork, timeout); ++ ++ /* Skip ahead to preserve error code set above. */ ++ goto out_wait; ++ } ++ ++ release_sock(sk); ++ timeout = schedule_timeout(timeout); ++ lock_sock(sk); ++ ++ if (signal_pending(current)) { ++ ret = sock_intr_errno(timeout); ++ goto out_wait_error; ++ } else if (timeout == 0) { ++ ret = -ETIMEDOUT; ++ goto out_wait_error; ++ } ++ ++ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); ++ } ++ ++ ret = sk->sk_err ? -sk->sk_err : 0; ++ ++out_wait_error: ++ if (ret < 0) { ++ sk->sk_state = SS_UNCONNECTED; ++ sock->state = SS_UNCONNECTED; ++ } ++out_wait: ++ finish_wait(sk_sleep(sk), &wait); ++ return ret; ++} ++ +static int hvsock_connect(struct socket *sock, struct sockaddr *addr, + int addr_len, int flags) +{ + struct sockaddr_hv *remote_addr; + struct hvsock_sock *hvsk; + struct sock *sk; -+ -+ DEFINE_WAIT(wait); -+ long timeout; -+ + int ret = 0; + + sk = sock->sk; @@ -1051,85 +1134,23 @@ index 0000000..e5639eb + ret = -EINPROGRESS; + } + -+ /* The receive path will handle all communication until we are able to -+ * enter the connected state. Here we wait for the connection to be -+ * completed or a notification of an error. -+ */ -+ timeout = 30 * HZ; -+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); -+ -+ while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) { -+ if (flags & O_NONBLOCK) { -+ /* If we're not going to block, we schedule a timeout -+ * function to generate a timeout on the connection -+ * attempt, in case the peer doesn't respond in a -+ * timely manner. We hold on to the socket until the -+ * timeout fires. -+ */ -+ sock_hold(sk); -+ INIT_DELAYED_WORK(&hvsk->dwork, -+ hvsock_connect_timeout); -+ schedule_delayed_work(&hvsk->dwork, timeout); -+ -+ /* Skip ahead to preserve error code set above. */ -+ goto out_wait; -+ } -+ -+ release_sock(sk); -+ timeout = schedule_timeout(timeout); -+ lock_sock(sk); -+ -+ if (signal_pending(current)) { -+ ret = sock_intr_errno(timeout); -+ goto out_wait_error; -+ } else if (timeout == 0) { -+ ret = -ETIMEDOUT; -+ goto out_wait_error; -+ } -+ -+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); -+ } -+ -+ ret = sk->sk_err ? -sk->sk_err : 0; -+ -+out_wait_error: -+ if (ret < 0) { -+ sk->sk_state = SS_UNCONNECTED; -+ sock->state = SS_UNCONNECTED; -+ } -+out_wait: -+ finish_wait(sk_sleep(sk), &wait); ++ ret = hvsock_connect_wait(sock, flags, ret); +out: + release_sock(sk); + return ret; +} + -+static -+int hvsock_accept(struct socket *sock, struct socket *newsock, int flags) ++static int hvsock_accept_wait(struct sock *listener, ++ struct socket *newsock, int flags) +{ + struct hvsock_sock *hvconnected; + struct sock *connected; -+ struct sock *listener; + + DEFINE_WAIT(wait); + long timeout; + + int ret = 0; + -+ listener = sock->sk; -+ -+ lock_sock(listener); -+ -+ if (sock->type != SOCK_STREAM) { -+ ret = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ if (listener->sk_state != SS_LISTEN) { -+ ret = -EINVAL; -+ goto out; -+ } -+ + /* Wait for children sockets to appear; these are the new sockets + * created upon connection establishment. + */ @@ -1160,27 +1181,43 @@ index 0000000..e5639eb + lock_sock(connected); + hvconnected = sk_to_hvsock(connected); + -+ /* If the listener socket has received an error, then we should -+ * reject this socket and return. Note that we simply mark the -+ * socket rejected, drop our reference, and let the cleanup -+ * function handle the cleanup; the fact that we found it in -+ * the listener's accept queue guarantees that the cleanup -+ * function hasn't run yet. -+ */ + if (ret) { + release_sock(connected); + sock_put(connected); -+ goto out_wait; ++ } else { ++ newsock->state = SS_CONNECTED; ++ sock_graft(connected, newsock); ++ release_sock(connected); ++ sock_put(connected); + } -+ -+ newsock->state = SS_CONNECTED; -+ sock_graft(connected, newsock); -+ release_sock(connected); -+ sock_put(connected); + } + +out_wait: + finish_wait(sk_sleep(listener), &wait); ++ return ret; ++} ++ ++static ++int hvsock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ struct sock *listener; ++ int ret; ++ ++ listener = sock->sk; ++ ++ lock_sock(listener); ++ ++ if (sock->type != SOCK_STREAM) { ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ if (listener->sk_state != SS_LISTEN) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ret = hvsock_accept_wait(listener, newsock, flags); +out: + release_sock(listener); + return ret; @@ -1227,93 +1264,37 @@ index 0000000..e5639eb + return ret; +} + -+static int hvsock_setsockopt(struct socket *sock, -+ int level, -+ int optname, -+ char __user *optval, unsigned int optlen) -+{ -+ return -ENOPROTOOPT; -+} -+ -+static int hvsock_getsockopt(struct socket *sock, -+ int level, -+ int optname, -+ char __user *optval, int __user *optlen) -+{ -+ return -ENOPROTOOPT; -+} -+ +static int hvsock_send_data(struct vmbus_channel *channel, + struct hvsock_sock *hvsk, + size_t to_write) +{ -+ hvsk->send.hdr.pkt_type = 1; -+ hvsk->send.hdr.data_size = to_write; -+ return vmbus_sendpacket(channel, &hvsk->send.hdr, -+ sizeof(hvsk->send.hdr) + to_write, ++ hvsk->send->hdr.pkt_type = 1; ++ hvsk->send->hdr.data_size = to_write; ++ return vmbus_sendpacket(channel, &hvsk->send->hdr, ++ sizeof(hvsk->send->hdr) + to_write, + 0, VM_PKT_DATA_INBAND, 0); +} + -+static int hvsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ++static ++int hvsock_sendmsg_wait(struct sock *sk, struct msghdr *msg, size_t len) +{ -+ struct vmbus_channel *channel; -+ struct hvsock_sock *hvsk; -+ struct sock *sk; ++ struct hvsock_sock *hvsk = sk_to_hvsock(sk); ++ struct vmbus_channel *channel = hvsk->channel; + + size_t total_to_write = len; + size_t total_written = 0; -+ + bool can_write; -+ long timeout; ++ + int ret = 0; + + DEFINE_WAIT(wait); -+ -+ if (len == 0) -+ return -EINVAL; -+ -+ if (msg->msg_flags & ~MSG_DONTWAIT) { -+ pr_err("hvsock_sendmsg: unsupported flags=0x%x\n", -+ msg->msg_flags); -+ return -EOPNOTSUPP; -+ } -+ -+ sk = sock->sk; -+ hvsk = sk_to_hvsock(sk); -+ channel = hvsk->channel; -+ -+ lock_sock(sk); -+ -+ /* Callers should not provide a destination with stream sockets. */ -+ if (msg->msg_namelen) { -+ ret = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ /* Send data only if both sides are not shutdown in the direction. */ -+ if (sk->sk_shutdown & SEND_SHUTDOWN || -+ hvsk->peer_shutdown & RCV_SHUTDOWN) { -+ ret = -EPIPE; -+ goto out; -+ } -+ -+ if (sk->sk_state != SS_CONNECTED || -+ !hvsock_addr_bound(&hvsk->local_addr)) { -+ ret = -ENOTCONN; -+ goto out; -+ } -+ -+ if (!hvsock_addr_bound(&hvsk->remote_addr)) { -+ ret = -EDESTADDRREQ; -+ goto out; -+ } ++ long timeout; + + timeout = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); -+ + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + + while (total_to_write > 0) { -+ size_t to_write; ++ size_t to_write, max_writable; + + while (1) { + get_ringbuffer_rw_status(channel, NULL, &can_write); @@ -1364,9 +1345,16 @@ index 0000000..e5639eb + * check how many bytes we actually wrote. + */ + do { ++ max_writable = get_ringbuffer_writable_bytes(channel); ++ if (max_writable == 0) ++ goto out_wait; ++ + to_write = min_t(size_t, HVSOCK_SND_BUF_SZ, + total_to_write); -+ ret = memcpy_from_msg(hvsk->send.buf, msg, to_write); ++ if (to_write > max_writable) ++ to_write = max_writable; ++ ++ ret = memcpy_from_msg(hvsk->send->buf, msg, to_write); + if (ret != 0) + goto out_wait; + @@ -1378,11 +1366,60 @@ index 0000000..e5639eb + total_to_write -= to_write; + } while (total_to_write > 0); + } ++ +out_wait: + if (total_written > 0) + ret = total_written; + + finish_wait(sk_sleep(sk), &wait); ++ return ret; ++} ++ ++static int hvsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) ++{ ++ struct hvsock_sock *hvsk; ++ struct sock *sk; ++ int ret; ++ ++ if (len == 0) ++ return -EINVAL; ++ ++ if (msg->msg_flags & ~MSG_DONTWAIT) { ++ pr_err("%s: unsupported flags=0x%x\n", __func__, ++ msg->msg_flags); ++ return -EOPNOTSUPP; ++ } ++ ++ sk = sock->sk; ++ hvsk = sk_to_hvsock(sk); ++ ++ lock_sock(sk); ++ ++ /* Callers should not provide a destination with stream sockets. */ ++ if (msg->msg_namelen) { ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ /* Send data only if both sides are not shutdown in the direction. */ ++ if (sk->sk_shutdown & SEND_SHUTDOWN || ++ hvsk->peer_shutdown & RCV_SHUTDOWN) { ++ ret = -EPIPE; ++ goto out; ++ } ++ ++ if (sk->sk_state != SS_CONNECTED || ++ !hvsock_addr_bound(&hvsk->local_addr)) { ++ ret = -ENOTCONN; ++ goto out; ++ } ++ ++ if (!hvsock_addr_bound(&hvsk->remote_addr)) { ++ ret = -EDESTADDRREQ; ++ goto out; ++ } ++ ++ ret = hvsock_sendmsg_wait(sk, msg, len); +out: + release_sock(sk); + @@ -1403,85 +1440,38 @@ index 0000000..e5639eb + u64 dummy_req_id; + int ret; + -+ ret = vmbus_recvpacket(channel, &hvsk->recv.hdr, -+ sizeof(hvsk->recv.hdr) + sizeof(hvsk->recv.buf), ++ ret = vmbus_recvpacket(channel, &hvsk->recv->hdr, ++ sizeof(hvsk->recv->hdr) + ++ sizeof(hvsk->recv->buf), + &buffer_actual_len, &dummy_req_id); -+ if (ret != 0 || buffer_actual_len <= sizeof(hvsk->recv.hdr)) ++ if (ret != 0 || buffer_actual_len <= sizeof(hvsk->recv->hdr)) + *payload_len = 0; + else -+ *payload_len = hvsk->recv.hdr.data_size; ++ *payload_len = hvsk->recv->hdr.data_size; + + return ret; +} + -+static int hvsock_recvmsg(struct socket *sock, struct msghdr *msg, -+ size_t len, int flags) ++static int hvsock_recvmsg_wait(struct sock *sk, struct msghdr *msg, ++ size_t len, int flags) +{ -+ struct vmbus_channel *channel; -+ struct hvsock_sock *hvsk; -+ struct sock *sk; -+ -+ size_t total_to_read = len; -+ size_t copied; ++ struct hvsock_sock *hvsk = sk_to_hvsock(sk); ++ struct vmbus_channel *channel = hvsk->channel; + ++ size_t to_read, total_to_read = len; ++ size_t copied = 0; + bool can_read; -+ long timeout; + + int ret = 0; + + DEFINE_WAIT(wait); -+ -+ sk = sock->sk; -+ hvsk = sk_to_hvsock(sk); -+ channel = hvsk->channel; -+ -+ lock_sock(sk); -+ -+ if (sk->sk_state != SS_CONNECTED) { -+ /* Recvmsg is supposed to return 0 if a peer performs an -+ * orderly shutdown. Differentiate between that case and when a -+ * peer has not connected or a local shutdown occurred with the -+ * SOCK_DONE flag. -+ */ -+ if (sock_flag(sk, SOCK_DONE)) -+ ret = 0; -+ else -+ ret = -ENOTCONN; -+ -+ goto out; -+ } -+ -+ /* We ignore msg->addr_name/len. */ -+ if (flags & ~MSG_DONTWAIT) { -+ pr_err("hvsock_recvmsg: unsupported flags=0x%x\n", flags); -+ ret = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ /* We don't check peer_shutdown flag here since peer may actually shut -+ * down, but there can be data in the queue that a local socket can -+ * receive. -+ */ -+ if (sk->sk_shutdown & RCV_SHUTDOWN) { -+ ret = 0; -+ goto out; -+ } -+ -+ /* It is valid on Linux to pass in a zero-length receive buffer. This -+ * is not an error. We may as well bail out now. -+ */ -+ if (!len) { -+ ret = 0; -+ goto out; -+ } ++ long timeout; + + timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); -+ copied = 0; -+ + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + + while (1) { -+ bool need_refill = hvsk->recv.data_len == 0; ++ bool need_refill = hvsk->recv->data_len == 0; + + if (need_refill) + get_ringbuffer_rw_status(channel, &can_read, NULL); @@ -1494,43 +1484,42 @@ index 0000000..e5639eb + if (need_refill) { + ret = hvsock_recv_data(channel, hvsk, + &payload_len); -+ if (ret != 0 || payload_len == 0 || ++ if (ret != 0 || + payload_len > HVSOCK_RCV_BUF_SZ) { + ret = -EIO; + goto out_wait; + } + -+ hvsk->recv.data_len = payload_len; -+ hvsk->recv.data_offset = 0; ++ if (payload_len == 0) { ++ ret = copied; ++ goto out_wait; ++ } ++ ++ hvsk->recv->data_len = payload_len; ++ hvsk->recv->data_offset = 0; + } + -+ if (hvsk->recv.data_len <= total_to_read) { -+ ret = memcpy_to_msg(msg, hvsk->recv.buf + -+ hvsk->recv.data_offset, -+ hvsk->recv.data_len); -+ if (ret != 0) -+ break; ++ to_read = min_t(size_t, total_to_read, ++ hvsk->recv->data_len); + -+ copied += hvsk->recv.data_len; -+ total_to_read -= hvsk->recv.data_len; -+ hvsk->recv.data_len = 0; -+ hvsk->recv.data_offset = 0; -+ -+ if (total_to_read == 0) -+ break; -+ } else { -+ ret = memcpy_to_msg(msg, hvsk->recv.buf + -+ hvsk->recv.data_offset, -+ total_to_read); -+ if (ret != 0) -+ break; -+ -+ copied += total_to_read; -+ hvsk->recv.data_len -= total_to_read; -+ hvsk->recv.data_offset += total_to_read; -+ total_to_read = 0; ++ ret = memcpy_to_msg(msg, hvsk->recv->buf + ++ hvsk->recv->data_offset, ++ to_read); ++ if (ret != 0) ++ break; ++ ++ copied += to_read; ++ total_to_read -= to_read; ++ ++ hvsk->recv->data_len -= to_read; ++ ++ if (hvsk->recv->data_len == 0) ++ hvsk->recv->data_offset = 0; ++ else ++ hvsk->recv->data_offset += to_read; ++ ++ if (total_to_read == 0) + break; -+ } + } else { + if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || + (hvsk->peer_shutdown & SEND_SHUTDOWN)) @@ -1575,7 +1564,7 @@ index 0000000..e5639eb + * state. + */ + if ((hvsk->peer_shutdown & SEND_SHUTDOWN) && -+ hvsk->recv.data_len == 0) { ++ hvsk->recv->data_len == 0) { + get_ringbuffer_rw_status(channel, &can_read, NULL); + if (!can_read) { + sk->sk_state = SS_UNCONNECTED; @@ -1586,6 +1575,56 @@ index 0000000..e5639eb + } +out_wait: + finish_wait(sk_sleep(sk), &wait); ++ return ret; ++} ++ ++static int hvsock_recvmsg(struct socket *sock, struct msghdr *msg, ++ size_t len, int flags) ++{ ++ struct sock *sk = sock->sk; ++ int ret; ++ ++ lock_sock(sk); ++ ++ if (sk->sk_state != SS_CONNECTED) { ++ /* Recvmsg is supposed to return 0 if a peer performs an ++ * orderly shutdown. Differentiate between that case and when a ++ * peer has not connected or a local shutdown occurred with the ++ * SOCK_DONE flag. ++ */ ++ if (sock_flag(sk, SOCK_DONE)) ++ ret = 0; ++ else ++ ret = -ENOTCONN; ++ ++ goto out; ++ } ++ ++ /* We ignore msg->addr_name/len. */ ++ if (flags & ~MSG_DONTWAIT) { ++ pr_err("%s: unsupported flags=0x%x\n", __func__, flags); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ /* We don't check peer_shutdown flag here since peer may actually shut ++ * down, but there can be data in the queue that a local socket can ++ * receive. ++ */ ++ if (sk->sk_shutdown & RCV_SHUTDOWN) { ++ ret = 0; ++ goto out; ++ } ++ ++ /* It is valid on Linux to pass in a zero-length receive buffer. This ++ * is not an error. We may as well bail out now. ++ */ ++ if (!len) { ++ ret = 0; ++ goto out; ++ } ++ ++ ret = hvsock_recvmsg_wait(sk, msg, len, flags); +out: + release_sock(sk); + return ret; @@ -1604,8 +1643,8 @@ index 0000000..e5639eb + .ioctl = sock_no_ioctl, + .listen = hvsock_listen, + .shutdown = hvsock_shutdown, -+ .setsockopt = hvsock_setsockopt, -+ .getsockopt = hvsock_getsockopt, ++ .setsockopt = sock_no_setsockopt, ++ .getsockopt = sock_no_getsockopt, + .sendmsg = hvsock_sendmsg, + .recvmsg = hvsock_recvmsg, + .mmap = sock_no_mmap, @@ -1680,7 +1719,7 @@ index 0000000..e5639eb +{ + int ret; + -+ /* Hyper-V socket requires at least VMBus 4.0 */ ++ /* Hyper-V Sockets requires at least VMBus 4.0 */ + if ((vmbus_proto_version >> 16) < 4) { + pr_err("failed to load: VMBus 4 or later is required\n"); + return -ENODEV; @@ -1726,5 +1765,5 @@ index 0000000..e5639eb +MODULE_DESCRIPTION("Hyper-V Sockets"); +MODULE_LICENSE("Dual BSD/GPL"); -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0025-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch b/alpine/kernel/patches/0026-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch similarity index 93% rename from alpine/kernel/patches/0025-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch rename to alpine/kernel/patches/0026-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch index af0d9b569..6e0a37768 100644 --- a/alpine/kernel/patches/0025-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch +++ b/alpine/kernel/patches/0026-net-add-the-AF_HYPERV-entries-to-family-name-tables.patch @@ -1,7 +1,7 @@ -From 0198717a05de80bc7769ed1d2c3a0cdf3c40fd7c Mon Sep 17 00:00:00 2001 +From 9e6fe61e17afc54313f2fd8216c1c8aa150f97e7 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 21 Mar 2016 02:53:08 -0700 -Subject: [PATCH 25/26] net: add the AF_HYPERV entries to family name tables +Subject: [PATCH 26/27] net: add the AF_HYPERV entries to family name tables This is for the hv_sock driver, which introduces AF_HYPERV(42). @@ -45,5 +45,5 @@ index 925def4..323f7a3 100644 /* -- -2.8.0.rc3 +2.8.2 diff --git a/alpine/kernel/patches/0026-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch b/alpine/kernel/patches/0027-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch similarity index 93% rename from alpine/kernel/patches/0026-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch rename to alpine/kernel/patches/0027-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch index 3e7cb4e98..774aefbfd 100644 --- a/alpine/kernel/patches/0026-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch +++ b/alpine/kernel/patches/0027-VSOCK-do-not-disconnect-socket-when-peer-has-shutdow.patch @@ -1,7 +1,7 @@ -From a0ae608df96d0059ffa2e0561ff0a53aa298adca Mon Sep 17 00:00:00 2001 +From 637d86f5133f5c0a446dcce0d1dd6006bc9a3b4d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 4 May 2016 14:21:53 +0100 -Subject: [PATCH 26/26] VSOCK: do not disconnect socket when peer has shutdown +Subject: [PATCH 27/27] VSOCK: do not disconnect socket when peer has shutdown SEND only The peer may be expecting a reply having sent a request and then done a @@ -64,5 +64,5 @@ index ead5127..8373709 100644 out: release_sock(sk); -- -2.8.0.rc3 +2.8.2