From nobody Wed Feb 11 02:39:26 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1598270152; cv=none; d=zohomail.com; s=zohoarc; b=N/AokN4HegwGjf9SkAnAPGxbbOcDMFrrd4SlVQa0zL4Qhq3k1mw350MAWbGrVh3b9noZSvyRZ5P+a6QkD2vsU9qijJ0ObwTHIfCxAlrqa3GaQaw0hMlX4kmvNt2eFkbvLIApBmW9ru3wKCxcibWqHWnV+88ci/BFfFUNACMklww= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1598270152; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=1Whg2mc5iyxnrIkOgqe4IhGahSTXU0yG89+O6eLQVY8=; b=Rq6pgXr1r7AtZDhCOub7pAf5KSxK91BeSOubyjBmQIbtwKA3fEFTyvQqgQEQA43MbtylIwPw8KXz8s+4kx/UVvsdDOee+FaX4Q24rHP+JVBl8kDyCeXD+SiOkn68xM03EUnyFoL3BD4842JIVVL+D524ss4cM5ikHL5GZymX0e4= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1598270152156235.51387158943282; Mon, 24 Aug 2020 04:55:52 -0700 (PDT) Received: from localhost ([::1]:59536 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kAB4o-0005zM-PG for importer@patchew.org; Mon, 24 Aug 2020 07:55:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51522) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kAAyj-00034n-V2 for qemu-devel@nongnu.org; Mon, 24 Aug 2020 07:49:33 -0400 Received: from gate-2.cri.epita.net ([163.5.55.20]:54860 helo=mail-2.srv.cri.epita.fr) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kAAyh-0003eF-H4 for qemu-devel@nongnu.org; Mon, 24 Aug 2020 07:49:33 -0400 Received: from MattGorko-Laptop.home (lfbn-idf1-1-1395-83.w90-79.abo.wanadoo.fr [90.79.87.83]) (Authenticated sender: cesar.belley) by mail-2.srv.cri.epita.fr (Postfix) with ESMTPSA id 3FEA53FAC7; Mon, 24 Aug 2020 13:49:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=lse.epita.fr; s=cri; t=1598269760; bh=hKpGvvq0chDFquaLVg/SoDp2sQXaURAZyryEMSCPX1s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DoKDykgc0fzo8vagx/A3/0KCHvGmVGNK/HApubrJyHavgexBd6LYGfTQWRvOPc6VC GyE1wauhTPPj4QgGqML1191jV2bo+pf3MiDCyAuvnDyptGrYp0Jh3E2aFyK7YF9y6X HxzDWu3QvfNJvWwzqKz3gBNGlPRfhYvY1grCSpUU= From: =?UTF-8?q?C=C3=A9sar=20Belley?= To: qemu-devel@nongnu.org Subject: [PATCH v2 13/13] hw/usb: Add U2F device autoscan to passthru mode Date: Mon, 24 Aug 2020 13:48:27 +0200 Message-Id: <20200824114827.81623-14-cesar.belley@lse.epita.fr> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200824114827.81623-1-cesar.belley@lse.epita.fr> References: <20200824114827.81623-1-cesar.belley@lse.epita.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=163.5.55.20; envelope-from=srs0=45nv=cc=lse.epita.fr=cesar.belley@cri.epita.fr; helo=mail-2.srv.cri.epita.fr X-detected-operating-system: by eggs.gnu.org: First seen = 2020/08/24 07:49:04 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?C=C3=A9sar=20Belley?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: C=C3=A9sar Belley --- docs/u2f.txt | 9 ++++ hw/usb/meson.build | 2 +- hw/usb/u2f-passthru.c | 113 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/docs/u2f.txt b/docs/u2f.txt index f60052882e..8f44994818 100644 --- a/docs/u2f.txt +++ b/docs/u2f.txt @@ -42,6 +42,10 @@ on libu2f-emu: configuring and building: =20 ./configure --enable-u2f && make =20 +The pass-through mode is built by default on Linux. To take advantage +of the autoscan option it provides, make sure you have a working libudev +installed on the host. + =20 3. Using u2f-emulated =20 @@ -90,6 +94,11 @@ On the host specify the u2f-passthru device with a suita= ble hidraw: =20 qemu -usb -device u2f-passthru,hidraw=3D/dev/hidraw0 =20 +Alternately, the u2f-passthru device can autoscan to take the first +U2F device it finds on the host (this requires a working libudev): + + qemu -usb -device u2f-passthru + =20 5. Libu2f-emu =20 diff --git a/hw/usb/meson.build b/hw/usb/meson.build index cac7639924..40c283ceb5 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -52,7 +52,7 @@ endif =20 # U2F softmmu_ss.add(when: 'CONFIG_USB_U2F', if_true: files('u2f.c')) -softmmu_ss.add(when: ['CONFIG_LINUX', 'CONFIG_USB_U2F'], if_true: files('u= 2f-passthru.c')) +softmmu_ss.add(when: ['CONFIG_LINUX', 'CONFIG_USB_U2F'], if_true: [libudev= , files('u2f-passthru.c')]) softmmu_ss.add(when: ['CONFIG_U2F', 'CONFIG_USB_U2F'], if_true: [u2f, file= s('u2f-emulated.c')]) =20 # usb redirect diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index f8771966c7..1311530ee5 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -378,6 +378,84 @@ static bool u2f_passthru_is_u2f_device(int fd) sizeof(u2f_hid_report_desc_header)) =3D=3D 0; } =20 +#ifdef CONFIG_LIBUDEV +static int u2f_passthru_open_from_device(struct udev_device *device) +{ + const char *devnode =3D udev_device_get_devnode(device); + + int fd =3D qemu_open(devnode, O_RDWR); + if (fd < 0) { + return -1; + } else if (!u2f_passthru_is_u2f_device(fd)) { + qemu_close(fd); + return -1; + } + return fd; +} + +static int u2f_passthru_open_from_enumerate(struct udev *udev, + struct udev_enumerate *enumera= te) +{ + struct udev_list_entry *devices, *entry; + int ret, fd; + + ret =3D udev_enumerate_scan_devices(enumerate); + if (ret < 0) { + return -1; + } + + devices =3D udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(entry, devices) { + struct udev_device *device; + const char *syspath =3D udev_list_entry_get_name(entry); + + if (syspath =3D=3D NULL) { + continue; + } + + device =3D udev_device_new_from_syspath(udev, syspath); + if (device =3D=3D NULL) { + continue; + } + + fd =3D u2f_passthru_open_from_device(device); + udev_device_unref(device); + if (fd >=3D 0) { + return fd; + } + } + return -1; +} + +static int u2f_passthru_open_from_scan(void) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + int ret, fd =3D -1; + + udev =3D udev_new(); + if (udev =3D=3D NULL) { + return -1; + } + + enumerate =3D udev_enumerate_new(udev); + if (enumerate =3D=3D NULL) { + udev_unref(udev); + return -1; + } + + ret =3D udev_enumerate_add_match_subsystem(enumerate, "hidraw"); + if (ret >=3D 0) { + fd =3D u2f_passthru_open_from_enumerate(udev, enumerate); + } + + udev_enumerate_unref(enumerate); + udev_unref(udev); + + return fd; +} +#endif + static void u2f_passthru_unrealize(U2FKeyState *base) { U2FPassthruState *key =3D PASSTHRU_U2F_KEY(base); @@ -392,22 +470,31 @@ static void u2f_passthru_realize(U2FKeyState *base, E= rror **errp) int fd; =20 if (key->hidraw =3D=3D NULL) { +#ifdef CONFIG_LIBUDEV + fd =3D u2f_passthru_open_from_scan(); + if (fd < 0) { + error_setg(errp, "%s: Failed to find a U2F USB device", + TYPE_U2F_PASSTHRU); + return; + } +#else error_setg(errp, "%s: Missing hidraw", TYPE_U2F_PASSTHRU); return; - } - - fd =3D qemu_open(key->hidraw, O_RDWR); - if (fd < 0) { - error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU, - key->hidraw); - return; - } +#endif + } else { + fd =3D qemu_open(key->hidraw, O_RDWR); + if (fd < 0) { + error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU, + key->hidraw); + return; + } =20 - if (!u2f_passthru_is_u2f_device(fd)) { - qemu_close(fd); - error_setg(errp, "%s: Passed hidraw does not represent " - "a U2F HID device", TYPE_U2F_PASSTHRU); - return; + if (!u2f_passthru_is_u2f_device(fd)) { + qemu_close(fd); + error_setg(errp, "%s: Passed hidraw does not represent " + "a U2F HID device", TYPE_U2F_PASSTHRU); + return; + } } key->hidraw_fd =3D fd; u2f_passthru_reset(key); --=20 2.28.0