From patchwork Tue Nov 30 22:24:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lars Gunnarsson X-Patchwork-Id: 518841 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86F27C433EF for ; Tue, 30 Nov 2021 22:24:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235522AbhK3W1j (ORCPT ); Tue, 30 Nov 2021 17:27:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53330 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233339AbhK3W1i (ORCPT ); Tue, 30 Nov 2021 17:27:38 -0500 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C58C4C061574 for ; Tue, 30 Nov 2021 14:24:18 -0800 (PST) Received: by mail-lf1-x136.google.com with SMTP id bi37so57581232lfb.5 for ; Tue, 30 Nov 2021 14:24:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=date:from:to:subject:message-id:mime-version:content-disposition; bh=1H/x1jtS428DpQJ3lNVu6wlNyGJDFqXHOdzCh0Gbpms=; b=Fpv7rRggkxsO5BV/buNVMk6jM27hpEQ5BVV6PnEs/0qm9Vay5myLzodAw8eGHBudLx V2y05GHGgCAFoakW5fGKjN4G3zqi5/xjPgpq70QYe2P06ucPgJOV84aOO+N3BKGTCr34 55or8KOJIjxjPUFyuLqpz1rW4aYP6V8UDiwPwej2VqxAdjoppdeVSl9e7SSIPQZUJxKL Ymj4ke6OvdRLxMKHz5LdWxJsG7q/waaepbzLIImGs2Qcmvf0J48i7en2nMytGcx3ORXc VNaqtJBKXgsHbFUbu2mLeMU+HtNkW1wzJ5bFlvjtCG7BdH2Czk5Gy0b/CccI4w59Mmb/ rtog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition; bh=1H/x1jtS428DpQJ3lNVu6wlNyGJDFqXHOdzCh0Gbpms=; b=P279XIbv5dmHeWeZyiKtlnxn9CJw4fF97/WfLx9a/q0PC6WphuSRKkWlecfu7iUN2d 5zH3gmwaM99s8qdVsWxJV9ivvlSr7eOp/O7MPgOxYqEpKkLiSxBal6MLciqJkvyVRyBK knp6NGS2pmbyX80tcyXGSHtDw89H8+MlYgUTwvEs0XMWfed8gJck1nw2tXquUE0zU5he BQPlOY6CRxDmLEZvu0WF2S8eDrbbk6rqyFgVrZ7lKFyDt+f+sMmI0lqPS98xt5GwqtEg 3Zk+JBbQloSmpOljaMv9jWw3zIK0vuIVZ7zYyPZ+b8XxtdcgHMCcBn0cYXBNpASlIIns FnUg== X-Gm-Message-State: AOAM531lj5r9mzH+v8s11eqLebnLoxQmFWQ/UbSwqTW19dTIW0U1y3bh FiiRZvvYDoi7UYowa+v4SwMmoviWGhY= X-Google-Smtp-Source: ABdhPJzWSPzgPaKa7U2lKkm0AXlmDIeIqsmXzkX4x1/dFbQYTrWmwptwoFZPtU4XrWowxByD/RSUuw== X-Received: by 2002:a19:c308:: with SMTP id t8mr1908253lff.621.1638311056775; Tue, 30 Nov 2021 14:24:16 -0800 (PST) Received: from dell-precision-T3610 (h-98-128-167-144.NA.cust.bahnhof.se. [98.128.167.144]) by smtp.gmail.com with ESMTPSA id o1sm1675468ljj.33.2021.11.30.14.24.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Nov 2021 14:24:16 -0800 (PST) Date: Tue, 30 Nov 2021 23:24:14 +0100 From: Lars Gunnarsson To: Valentina Manea , Shuah Khan , linux-usb@vger.kernel.org Subject: [PATCH v4 3/5] tools/usbip: add usb event monitor into libusbip Message-ID: <20211130222414.GA16520@dell-precision-T3610> MIME-Version: 1.0 Content-Disposition: inline Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This patch implements an usb monitor into libusbip to synchronously wait for usb events, which is used in coming patches. By hooking this api into "usb bind" before exporting a device, allows the command to wait for a device to be plugged in. By hooking this api in after a successful export allows the command to know when to restart bus monitoring again. By hooking this api into usbipd at the beginning of an import request, allows the command "usbip attach" to wait for a device to become exported. By hooking this api into "usbip attach" right after a successful import, allows the command to know when to restart remote bus monitoring again. Example of api usage: // wait for an usb divce to be plugged in: usbip_monitor_t *monitor = usbip_monitor_new(); usbip_monitor_set_busid(monitor, "3-3.1.2.3"); usbip_monitor_await_usb_bind(monitor, "usb"); // this is a blocking call // usb device with busid 3-3.1.2.3 is now bound to driver "usb". usbip_monitor_delete(monitor); Signed-off-by: Lars Gunnarsson --- v2: Change title, fix style warnings, improve feature description, add timeout into usbip_monitor. v3: Change title and description. v4: Change description and fix review comments. Justifications of remaining warnings from "scripts/checkpatch.pl": * Exception according to Linux kernel coding style 5.a where "usbip_monitor_t" is a totally opaque object: WARNING: do not add new typedefs #199: FILE: tools/usb/usbip/libsrc/usbip_monitor.h:8: +typedef struct usbip_monitor usbip_monitor_t; tools/usb/usbip/.gitignore | 1 + tools/usb/usbip/libsrc/Makefile.am | 3 +- tools/usb/usbip/libsrc/usbip_common.h | 1 + tools/usb/usbip/libsrc/usbip_monitor.c | 161 +++++++++++++++++++++++++ tools/usb/usbip/libsrc/usbip_monitor.h | 36 ++++++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 tools/usb/usbip/libsrc/usbip_monitor.c create mode 100644 tools/usb/usbip/libsrc/usbip_monitor.h -- 2.25.1 diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore index 597361a96dbb..6304adefb5e1 100644 --- a/tools/usb/usbip/.gitignore +++ b/tools/usb/usbip/.gitignore @@ -28,6 +28,7 @@ libsrc/libusbip_la-usbip_common.lo libsrc/libusbip_la-usbip_device_driver.lo libsrc/libusbip_la-usbip_host_common.lo libsrc/libusbip_la-usbip_host_driver.lo +libsrc/libusbip_la-usbip_monitor.lo libsrc/libusbip_la-vhci_driver.lo src/usbip src/usbipd diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am index dabd2c91d311..3e31e33729cf 100644 --- a/tools/usb/usbip/libsrc/Makefile.am +++ b/tools/usb/usbip/libsrc/Makefile.am @@ -8,4 +8,5 @@ libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ usbip_device_driver.c usbip_device_driver.h \ usbip_common.c usbip_common.h usbip_host_common.h \ usbip_host_common.c vhci_driver.c vhci_driver.h \ - sysfs_utils.c sysfs_utils.h + sysfs_utils.c sysfs_utils.h \ + usbip_monitor.c diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h index 73a367a7fa10..13f1d4ca47c5 100644 --- a/tools/usb/usbip/libsrc/usbip_common.h +++ b/tools/usb/usbip/libsrc/usbip_common.h @@ -30,6 +30,7 @@ /* kernel module names */ #define USBIP_CORE_MOD_NAME "usbip-core" +#define USBIP_USB_DRV_NAME "usb" #define USBIP_HOST_DRV_NAME "usbip-host" #define USBIP_DEVICE_DRV_NAME "usbip-vudc" #define USBIP_VHCI_DRV_NAME "vhci_hcd" diff --git a/tools/usb/usbip/libsrc/usbip_monitor.c b/tools/usb/usbip/libsrc/usbip_monitor.c new file mode 100644 index 000000000000..9facf6aff294 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_monitor.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * Copyright (C) 2021 Lars Gunnarsson + */ +#include +#include +#include +#include + +#include "usbip_monitor.h" + +struct usbip_monitor { + const char *busid; + int timeout_ms; + struct udev *udev; + struct udev_monitor *udev_monitor; +}; + +usbip_monitor_t *usbip_monitor_new(void) +{ + usbip_monitor_t *monitor = NULL; + struct udev *udev = udev_new(); + + if (udev) { + struct udev_monitor *udev_monitor = + udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype( + udev_monitor, "usb", "usb_device"); + udev_monitor_enable_receiving(udev_monitor); + monitor = malloc(sizeof(struct usbip_monitor)); + monitor->busid = NULL; + monitor->timeout_ms = -1; + monitor->udev = udev; + monitor->udev_monitor = udev_monitor; + } + return monitor; +} + +void usbip_monitor_delete(usbip_monitor_t *monitor) +{ + if (monitor) { + udev_monitor_unref(monitor->udev_monitor); + udev_unref(monitor->udev); + free(monitor); + } +} + +void usbip_monitor_set_busid(usbip_monitor_t *monitor, const char *busid) +{ + monitor->busid = busid; +} + +void usbip_monitor_set_timeout(usbip_monitor_t *monitor, int milliseconds) +{ + monitor->timeout_ms = milliseconds; +} + +static struct udev_device *await_udev_event(const usbip_monitor_t *monitor) +{ + struct udev_device *dev = NULL; + + if (monitor) { + int fd = udev_monitor_get_fd(monitor->udev_monitor); + const int nfds = 1; + struct pollfd pollfd[] = { { fd, POLLIN, 0 } }; + int nfd = poll(pollfd, nfds, monitor->timeout_ms); + + if (nfd) + dev = udev_monitor_receive_device( + monitor->udev_monitor); + } + return dev; +} + +static int optional_filter_busid(const char *busid, const char *udev_busid) +{ + int filter_match = 0; + + if (busid) { + if (strcmp(busid, udev_busid) == 0) + filter_match = 1; + } else { + filter_match = 1; + } + return filter_match; +} + +static bool await_usb_with_driver(const usbip_monitor_t *monitor, + const char *driver, const char *action) +{ + bool event_occured = false; + + while (!event_occured) { + struct udev_device *dev = await_udev_event(monitor); + + if (dev) { + const char *udev_action = udev_device_get_action(dev); + const char *udev_driver = udev_device_get_driver(dev); + const char *udev_busid = udev_device_get_sysname(dev); + + if (strcmp(udev_action, action) == 0 && + strcmp(udev_driver, driver) == 0) { + if (optional_filter_busid(monitor->busid, + udev_busid)) { + event_occured = true; + } + } + udev_device_unref(dev); + } else { + break; + } + } + return event_occured; +} + +bool usbip_monitor_await_usb_add(const usbip_monitor_t *monitor, + const char *driver) +{ + return await_usb_with_driver(monitor, driver, "add"); +} + +bool usbip_monitor_await_usb_bind(const usbip_monitor_t *monitor, + const char *driver) +{ + return await_usb_with_driver(monitor, driver, "bind"); +} + +static bool await_usb(const usbip_monitor_t *monitor, const char *action) +{ + bool event_occured = false; + + while (!event_occured) { + struct udev_device *dev = await_udev_event(monitor); + + if (dev) { + const char *udev_action = udev_device_get_action(dev); + const char *udev_busid = udev_device_get_sysname(dev); + + if (strcmp(udev_action, action) == 0) { + if (optional_filter_busid(monitor->busid, + udev_busid)) { + event_occured = true; + } + } + udev_device_unref(dev); + } else { + break; + } + } + return event_occured; +} + +bool usbip_monitor_await_usb_unbind(const usbip_monitor_t *monitor) +{ + return await_usb(monitor, "unbind"); +} + +bool usbip_monitor_await_usb_delete(const usbip_monitor_t *monitor) +{ + return await_usb(monitor, "delete"); +} diff --git a/tools/usb/usbip/libsrc/usbip_monitor.h b/tools/usb/usbip/libsrc/usbip_monitor.h new file mode 100644 index 000000000000..209bc722529c --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_monitor.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * Copyright (C) 2021 Lars Gunnarsson + */ +#ifndef __USBIP_MONITOR_H +#define __USBIP_MONITOR_H + +#include + +typedef struct usbip_monitor usbip_monitor_t; + +usbip_monitor_t *usbip_monitor_new(void); +void usbip_monitor_delete(usbip_monitor_t *monitor); + +/** + * Set busid to await events on. If unset, any busid will be matched. + */ +void usbip_monitor_set_busid(usbip_monitor_t *monitor, const char *busid); + +/** + * Set timeout for await calls in milliseconds, default is no timeout (-1). + */ +void usbip_monitor_set_timeout(usbip_monitor_t *monitor, int milliseconds); + +/** + * Functions below is blocking. Returns true if event occurred, or false on + * timeouts. + */ +bool usbip_monitor_await_usb_add(const usbip_monitor_t *monitor, + const char *driver); +bool usbip_monitor_await_usb_bind(const usbip_monitor_t *monitor, + const char *driver); +bool usbip_monitor_await_usb_unbind(const usbip_monitor_t *monitor); +bool usbip_monitor_await_usb_delete(const usbip_monitor_t *monitor); + +#endif /* __USBIP_MONITOR_H */ From patchwork Tue Nov 30 22:24:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lars Gunnarsson X-Patchwork-Id: 518840 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85A77C433F5 for ; Tue, 30 Nov 2021 22:25:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235887AbhK3W2U (ORCPT ); Tue, 30 Nov 2021 17:28:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235555AbhK3W2T (ORCPT ); Tue, 30 Nov 2021 17:28:19 -0500 Received: from mail-lj1-x236.google.com (mail-lj1-x236.google.com [IPv6:2a00:1450:4864:20::236]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 91BEAC061574 for ; Tue, 30 Nov 2021 14:24:59 -0800 (PST) Received: by mail-lj1-x236.google.com with SMTP id v15so44144259ljc.0 for ; Tue, 30 Nov 2021 14:24:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=date:from:to:subject:message-id:mime-version:content-disposition; bh=rZW+krZrU+ABnW+aALny+P/fhfizmGqDBwUt1VeURkA=; b=WsMWGU9It5GMfocCKCPzKJIBu2YXmGvQzLcdLHye5IuifFIySP0b5gf1W8wmBLeqtm J/ngFovOAD77+px/SI/ROb9lr4YmwrVT+PJJjpHDtCzPi36QvsG+XFGqKzi7YY20Sahg mcGrGxXObx01bplkTBKjToxnHLQypKLIbxBOUlG6zG2M2ib8ahvZDMXxjeL5QkpanB3H ckcpc00zYE1QRUOCc398eDVxtsA7AaakRg8IJXDkmdhKkJAO1leIRe9CM8UHOlAnKDmL pmX1tVvHAZ1FxbLS2ZEQX7XGtOSZATWLsw8QsxfVk6wnrU0pS9kvfK4kNERtc+lPhCrq XQZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition; bh=rZW+krZrU+ABnW+aALny+P/fhfizmGqDBwUt1VeURkA=; b=IytfC0Fdr8syMwvtdxgnoN9WihSeUNMQrb4EkygdXy4mIOf08BW56METn8A89gYZsl ej8K02Pc3pHBiALlOE+x2+icD111RtuZCJgWCqGAqikO4BtKpiY+/Az6gd3+tjzSZQ/a /FSNRYTSi31/7pv83o2UTCzXJ7+JLxhANUvRNljGAflVVPfTtGOp/kpJWonMYdg+D7dP uIMaTO+0v6QbOIk5rS92clSpOhZANXq8vjd3danFtns7Gn3WNcvO6jD4EBeZMTKTg5xz rL3vNP+S12vMYIJPnQtKAglhKfCAhD8RkVcErEEria+OBUjTweqCZuKdmcon3dl0xrED t4OQ== X-Gm-Message-State: AOAM531/lf7IL9JLY7rUnoyYiyUU993MlB0rJvBNGVAYrGfUkd2DszuT mdC3EGvRVoALyXNrIPiPNrMn7FiOtYQ= X-Google-Smtp-Source: ABdhPJzbUGEc3Q/Jb4mpj3uy3HhFZJL6AKZXBOMNQkOq+mNqFUdAhGXypXdYqLF0ixKsMvkf2Em4qA== X-Received: by 2002:a05:651c:503:: with SMTP id o3mr1636842ljp.353.1638311097882; Tue, 30 Nov 2021 14:24:57 -0800 (PST) Received: from dell-precision-T3610 (h-98-128-167-144.NA.cust.bahnhof.se. [98.128.167.144]) by smtp.gmail.com with ESMTPSA id n4sm2087402lfu.70.2021.11.30.14.24.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Nov 2021 14:24:57 -0800 (PST) Date: Tue, 30 Nov 2021 23:24:56 +0100 From: Lars Gunnarsson To: Valentina Manea , Shuah Khan , linux-usb@vger.kernel.org Subject: [PATCH v4 5/5] tools/usbip: import USB devices on a given bus persistently Message-ID: <20211130222456.GA16614@dell-precision-T3610> MIME-Version: 1.0 Content-Disposition: inline Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This patch extends the command "usbip attach" with flag "-p|--persistent". When this flag is used, devices on the given remote busid is imported when available, instead of returning an error if the device is not exported. When the usb device is unplugged, it will start monitor the given remote bus again. Increment protocol version to 1.1.2 (0x112) since this patch affects both ends: usbipd (server) and command "usbip attach" (client). Signed-off-by: Lars Gunnarsson --- v2: Change title, fix style warnings, improve feature description, refactor cmdline flag usage. v3: Change title and description. v4: Fix review comments. tools/usb/usbip/configure.ac | 2 +- tools/usb/usbip/libsrc/usbip_common.c | 1 + tools/usb/usbip/libsrc/usbip_common.h | 1 + tools/usb/usbip/libsrc/vhci_driver.c | 16 +++ tools/usb/usbip/libsrc/vhci_driver.h | 1 + tools/usb/usbip/src/usbip_attach.c | 134 +++++++++++++++++++------- tools/usb/usbip/src/usbip_network.h | 2 + tools/usb/usbip/src/usbipd.c | 93 ++++++++++++++++-- 8 files changed, 205 insertions(+), 45 deletions(-) -- 2.25.1 diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac index 607d05c5ccfd..156e42456423 100644 --- a/tools/usb/usbip/configure.ac +++ b/tools/usb/usbip/configure.ac @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org]) -AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number]) +AC_DEFINE([USBIP_VERSION], [0x00000112], [binary-coded decimal version number]) CURRENT=0 REVISION=1 diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c index b8d7d480595a..30efb6a9f76d 100644 --- a/tools/usb/usbip/libsrc/usbip_common.c +++ b/tools/usb/usbip/libsrc/usbip_common.c @@ -78,6 +78,7 @@ static struct op_common_status_string op_common_status_strings[] = { { ST_DEV_ERR, "Device in error state" }, { ST_NODEV, "Device not found" }, { ST_ERROR, "Unexpected response" }, + { ST_POLL_TIMEOUT, "Poll timeout" }, { 0, NULL} }; diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h index 13f1d4ca47c5..3df351877a33 100644 --- a/tools/usb/usbip/libsrc/usbip_common.h +++ b/tools/usb/usbip/libsrc/usbip_common.h @@ -53,6 +53,7 @@ #define ST_DEV_ERR 0x03 #define ST_NODEV 0x04 #define ST_ERROR 0x05 +#define ST_POLL_TIMEOUT 0x06 extern int usbip_use_syslog; extern int usbip_use_stderr; diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index 8159fd98680b..4fc75e8bad66 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -465,3 +465,19 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) return 0; } + +int usbip_vhci_get_local_busid_from(int port, char *local_busid) +{ + int rc = -1; + + for (int i = 0; i < vhci_driver->nports; ++i) { + struct usbip_imported_device *idev = &vhci_driver->idev[i]; + + if (idev->port == port && strnlen(idev->udev.busid, SYSFS_BUS_ID_SIZE)) { + memcpy(local_busid, idev->udev.busid, SYSFS_BUS_ID_SIZE); + rc = 0; + break; + } + } + return rc; +} diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index 6c9aca216705..4aecd4013cbe 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -63,5 +63,6 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, int usbip_vhci_detach_device(uint8_t port); int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); +int usbip_vhci_get_local_busid_from(int port, char *local_busid); #endif /* __VHCI_DRIVER_H */ diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index b4aeb9f1f493..27911d4dba0e 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -21,14 +22,23 @@ #include "vhci_driver.h" #include "usbip_common.h" +#include "usbip_monitor.h" #include "usbip_network.h" #include "usbip.h" +struct attach_options { + char *busid; + bool is_persistent; +}; + static const char usbip_attach_usage_string[] = "usbip attach \n" " -r, --remote= The machine with exported USB devices\n" - " -b, --busid= Busid of the device on \n" - " -d, --device= Id of the virtual UDC on \n"; + " -b, --busid= Busid of the device on \n" + " -d, --device= Id of the virtual UDC on \n" + " -p, --persistent Persistently monitor the given bus and import\n" + " USB devices when available on the remote end\n"; + void usbip_attach_usage(void) { @@ -117,7 +127,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev) return -1; } -static int query_import_device(int sockfd, char *busid) +static int query_import_device(int sockfd, char *busid, bool is_persistent) { int rc; struct op_import_request request; @@ -127,31 +137,35 @@ static int query_import_device(int sockfd, char *busid) memset(&request, 0, sizeof(request)); memset(&reply, 0, sizeof(reply)); - - /* send a request */ - rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); - if (rc < 0) { - err("send op_common"); - return -1; - } - strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); + if (is_persistent) { + request.poll_timeout_ms = 5000; + info("remote device on busid %s: polling", busid); + } + PACK_OP_IMPORT_REQUEST(1, &request); - PACK_OP_IMPORT_REQUEST(0, &request); + do { + /* send a request */ + rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); + if (rc < 0) { + err("send op_common"); + return -1; + } - rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); - if (rc < 0) { - err("send op_import_request"); - return -1; - } + rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); + if (rc < 0) { + err("send op_import_request"); + return -1; + } - /* receive a reply */ - rc = usbip_net_recv_op_common(sockfd, &code, &status); - if (rc < 0) { - err("Attach Request for %s failed - %s\n", - busid, usbip_op_common_status_string(status)); - return -1; - } + /* receive a reply */ + rc = usbip_net_recv_op_common(sockfd, &code, &status); + if (status != ST_POLL_TIMEOUT && rc < 0) { + err("Attach Request for %s failed - %s\n", + busid, usbip_op_common_status_string(status)); + return -1; + } + } while (status == ST_POLL_TIMEOUT); rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply)); if (rc < 0) { @@ -171,7 +185,17 @@ static int query_import_device(int sockfd, char *busid) return import_device(sockfd, &reply.udev); } -static int attach_device(char *host, char *busid) +static int get_local_busid_from(int port, char *local_busid) +{ + int rc = usbip_vhci_driver_open(); + + if (rc == 0) + rc = usbip_vhci_get_local_busid_from(port, local_busid); + usbip_vhci_driver_close(); + return rc; +} + +static int attach_device(char *host, struct attach_options opt) { int sockfd; int rc; @@ -183,19 +207,53 @@ static int attach_device(char *host, char *busid) return -1; } - rhport = query_import_device(sockfd, busid); + rhport = query_import_device(sockfd, opt.busid, opt.is_persistent); if (rhport < 0) return -1; close(sockfd); - rc = record_connection(host, usbip_port_string, busid, rhport); + rc = record_connection(host, usbip_port_string, opt.busid, rhport); if (rc < 0) { - err("record connection"); + err("Fail occurred when storing imported usbip device"); return -1; } + info("remote device on busid %s: attach complete", opt.busid); + return rhport; +} - return 0; +static void monitor_disconnect(usbip_monitor_t *monitor, char *busid, int rhport) +{ + // To monitor unbind we must first ensure to be at a bound state. To + // monitor bound state a local busid is needed, which is unknown at this + // moment. Local busid is not available until it's already bound to the usbip + // driver. Thus monitor bind events for any usb device until the busid is + // available for the port. + char local_busid[SYSFS_BUS_ID_SIZE] = {}; + + while (get_local_busid_from(rhport, local_busid)) + usbip_monitor_await_usb_bind(monitor, USBIP_USB_DRV_NAME); + info("remote device on busid %s: monitor disconnect", busid); + usbip_monitor_set_busid(monitor, local_busid); + usbip_monitor_await_usb_unbind(monitor); + usbip_monitor_set_busid(monitor, NULL); +} + +static int attach_device_persistently(char *host, struct attach_options opt) +{ + int rc = 0; + usbip_monitor_t *monitor = usbip_monitor_new(); + + while (rc == 0) { + int rhport = attach_device(host, opt); + + if (rhport < 0) + rc = -1; + else + monitor_disconnect(monitor, opt.busid, rhport); + } + usbip_monitor_delete(monitor); + return rc; } int usbip_attach(int argc, char *argv[]) @@ -204,15 +262,16 @@ int usbip_attach(int argc, char *argv[]) { "remote", required_argument, NULL, 'r' }, { "busid", required_argument, NULL, 'b' }, { "device", required_argument, NULL, 'd' }, + { "persistent", no_argument, NULL, 'p' }, { NULL, 0, NULL, 0 } }; char *host = NULL; - char *busid = NULL; + struct attach_options options = {}; int opt; int ret = -1; for (;;) { - opt = getopt_long(argc, argv, "d:r:b:", opts, NULL); + opt = getopt_long(argc, argv, "d:r:b:p", opts, NULL); if (opt == -1) break; @@ -223,17 +282,24 @@ int usbip_attach(int argc, char *argv[]) break; case 'd': case 'b': - busid = optarg; + options.busid = optarg; + break; + case 'p': + options.is_persistent = true; break; default: goto err_out; } } - if (!host || !busid) + if (!host || !options.busid) goto err_out; - ret = attach_device(host, busid); + if (options.is_persistent) + ret = attach_device_persistently(host, options); + else + ret = attach_device(host, options); + goto out; err_out: diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h index 83b4c5344f72..1c25d06ab688 100644 --- a/tools/usb/usbip/src/usbip_network.h +++ b/tools/usb/usbip/src/usbip_network.h @@ -61,6 +61,7 @@ struct op_devinfo_reply { struct op_import_request { char busid[SYSFS_BUS_ID_SIZE]; + uint32_t poll_timeout_ms; } __attribute__((packed)); struct op_import_reply { @@ -69,6 +70,7 @@ struct op_import_reply { } __attribute__((packed)); #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ + (request)->poll_timeout_ms = usbip_net_pack_uint32_t(pack, (request)->poll_timeout_ms);\ } while (0) #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index 48398a78e88a..36a81345474f 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef HAVE_LIBWRAP #include @@ -35,6 +36,7 @@ #include "usbip_host_common.h" #include "usbip_device_driver.h" #include "usbip_common.h" +#include "usbip_monitor.h" #include "usbip_network.h" #include "list.h" @@ -88,13 +90,78 @@ static void usbipd_help(void) printf("%s\n", usbipd_help_string); } +static struct usbip_exported_device *get_exported_device(const char *busid) +{ + struct usbip_exported_device *exported_dev = NULL; + struct usbip_exported_device *edev = NULL; + struct list_head *i; + + list_for_each(i, &driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); + if (!strncmp(busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { + exported_dev = edev; + break; + } + } + return exported_dev; +} + +static bool await_requested_device(usbip_monitor_t *monitor, + struct op_import_request *req) +{ + usbip_monitor_set_busid(monitor, req->busid); + usbip_monitor_set_timeout(monitor, req->poll_timeout_ms); + return usbip_monitor_await_usb_bind(monitor, "usbip-host"); +} + +static int recv_subsequent_poll_request(int sockfd, struct op_import_request *req) +{ + uint16_t code = OP_UNSPEC; + int status; + int rc = 0; + + rc = usbip_net_recv_op_common(sockfd, &code, &status); + if (rc < 0) { + dbg("could not receive opcode: %#0x", code); + return -1; + } + if (code != OP_REQ_IMPORT) { + dbg("Only subsequent OP_REQ_IMPORT allowed when polling"); + return -1; + } + rc = usbip_net_recv(sockfd, req, sizeof(struct op_import_request)); + if (rc < 0) { + dbg("Failed to receive incoming subsequent OP_REQ_IMPORT request"); + return -1; + } + PACK_OP_IMPORT_REQUEST(0, req); + return rc; +} + +static int monitor_requested_busid(int sockfd, struct op_import_request *req) +{ + int rc = 0; + usbip_monitor_t *monitor = usbip_monitor_new(); + + while (!await_requested_device(monitor, req)) { + int status = ST_POLL_TIMEOUT; + + rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, status); + if (rc < 0) { + dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT); + break; + } + rc = recv_subsequent_poll_request(sockfd, req); + } + usbip_monitor_delete(monitor); + return rc; +} + static int recv_request_import(int sockfd) { struct op_import_request req; - struct usbip_exported_device *edev; + struct usbip_exported_device *edev = NULL; struct usbip_usb_device pdu_udev; - struct list_head *i; - int found = 0; int status = ST_OK; int rc; @@ -107,16 +174,22 @@ static int recv_request_import(int sockfd) } PACK_OP_IMPORT_REQUEST(0, &req); - list_for_each(i, &driver->edev_list) { - edev = list_entry(i, struct usbip_exported_device, node); - if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { - info("found requested device: %s", req.busid); - found = 1; - break; + edev = get_exported_device(req.busid); + + if (!edev && req.poll_timeout_ms) { + info("Client polling for devices on busid: %s", req.busid); + rc = monitor_requested_busid(sockfd, &req); + if (rc < 0) { + dbg("Fail occurred when monitoring usb to become exported on busid: %s", + req.busid); + return -1; } + usbip_refresh_device_list(driver); + edev = get_exported_device(req.busid); } - if (found) { + if (edev) { + info("found requested device: %s", req.busid); /* should set TCP_NODELAY for usbip */ usbip_net_set_nodelay(sockfd);