From patchwork Tue Jan 16 01:49:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Grzeschik X-Patchwork-Id: 188355 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:693c:2614:b0:101:6a76:bbe3 with SMTP id mm20csp2051381dyc; Mon, 15 Jan 2024 17:56:56 -0800 (PST) X-Google-Smtp-Source: AGHT+IEvv3lh70lbhje5wN8P5YPbk17LmgbjPb0g6VAIwh3Xxp7/KYgGIlVSnkym1G/AGbQhSsCu X-Received: by 2002:ac2:5a01:0:b0:50e:c6fd:eb7e with SMTP id q1-20020ac25a01000000b0050ec6fdeb7emr2697170lfn.126.1705370216325; Mon, 15 Jan 2024 17:56:56 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705370216; cv=none; d=google.com; s=arc-20160816; b=I2FQSZ9uXYV/95YbSB5JrcBckOPOlGT919Crlss7JUzzwPUszimjzLkc0picYQUGW7 pQ0RUQ/xDel72YsVWuwzHEscq/w5nAm3axHcjE4c28MdrGmFaI87fZyW4vtoojk7KWLs KOvHPzTX8TJ90nEqXZWsrCbQrgrE2D0+VHlZnaqC12r0V70kl2XYmDgTZ7e764CWNtRj U9penslluDB25+27jIj6nUQsGaMXozyjmGzWJKdqvu3GG0CswUOsfZbJhcwHYPPZLRqw CJ1vYQeglmsKbBRQgjAFB1qciIrBSf8EL+r0pH4IvDTD0fNjsedVXjq/FH3gGEeUJdui t2pA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from; bh=kJ9/EYYjWKxdcfXs0F4ooN2UktM+1wkYd0dbf8rHlvs=; fh=j4kDYto2y5txw4kIsFBJWe3oUIncnYU+0HsCYPolsxs=; b=thA5spXijt443IA8/8vy3LxgDlE6YDn7BpMxeI8Ap+XSpdsDzpczPiU7NP89L3C5Zl fAfyAqMyDFWu8odjAZSFekQW7N5mrFg87SfpuFVmUg7TAsMzbK+Ie9yVuU77LR4ER1iC 9zx9nkgzdXL0La+jW6RTcVzrUR/TswpEwQ8Ky91OxozGDSZ15UnSEpC/+RORHseVsSO9 yPGyciMSjnyE/PlJviSjPePYUigTBaJ7s6yfX8zfIjK6RrWRKO2ekKTkClp024cvoRlx lE2/B7EX2q07V/OvpohmySwyyUYaqsypwGSKfaOz9gEAqAys3mpbDqoJ2c+Ou6Q6eeb+ +kCA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-26914-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-26914-ouuuleilei=gmail.com@vger.kernel.org" Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id m11-20020a1709066d0b00b00a28219b04desi4018030ejr.658.2024.01.15.17.56.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Jan 2024 17:56:56 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-26914-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-26914-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-26914-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 879511F239AC for ; Tue, 16 Jan 2024 01:56:55 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 410C1134B7; Tue, 16 Jan 2024 01:49:59 +0000 (UTC) Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3293A11C84 for ; Tue, 16 Jan 2024 01:49:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rPYaJ-0000l0-8h; Tue, 16 Jan 2024 02:49:47 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rPYaI-0008V8-1q; Tue, 16 Jan 2024 02:49:46 +0100 Received: from localhost ([::1] helo=dude04.red.stw.pengutronix.de) by dude04.red.stw.pengutronix.de with esmtp (Exim 4.96) (envelope-from ) id 1rPYaI-001Ipo-2o; Tue, 16 Jan 2024 02:49:45 +0100 From: Michael Grzeschik Date: Tue, 16 Jan 2024 02:49:43 +0100 Subject: [PATCH 3/3] tools: usb: p9_fwd: add usb gadget packet forwarder script Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240116-ml-topic-u9p-v1-3-ad8c306f9a4e@pengutronix.de> References: <20240116-ml-topic-u9p-v1-0-ad8c306f9a4e@pengutronix.de> In-Reply-To: <20240116-ml-topic-u9p-v1-0-ad8c306f9a4e@pengutronix.de> To: Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Jonathan Corbet , Greg Kroah-Hartman Cc: v9fs@lists.linux.dev, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, kernel@pengutronix.de, Michael Grzeschik X-Mailer: b4 0.12.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=7298; i=m.grzeschik@pengutronix.de; h=from:subject:message-id; bh=EtxiieN0JYb52VrhJMF3BYzOB7gYsb3PHk3p7PUt/uY=; b=owEBbQKS/ZANAwAKAb9pWET5cfSrAcsmYgBlpeC50whkdQK9oTjwyR3OGOBzQF/9NuFfcIlGM 4JzKAaiz5+JAjMEAAEKAB0WIQQV2+2Fpbqd6fvv0Gi/aVhE+XH0qwUCZaXguQAKCRC/aVhE+XH0 q0NlEACrX9qhdMDrs7Jx2/ZCTJbNatehVb2/8UEMELzjuGjVper3PENfxc/hAmwdMoIfy6915p/ 1FBAuuWaQVonNEJ0Ppx8pgWWJVoPiPM7F7cXyqUqTF4koBlPAWYBP+wufvFUnTUyAurhuGAXCbQ fPlw4GhMUdnJZBAAiJEjZ/o8/hc7B0QqQY46UgSzMv5zSlSrtlFNPl/E6XJgZGZop4NpR0zs06v tD8gBsTWj0MCiFq91eeBFL4q7676OjhKD3OBwj1aY8axsQ1/pSmDpOK7+0RRfb0JPi8C0wI7UrA qUeqxZHHmghDA0iZsEuqxM683Qykt7gYxmDDkq/AsKgFuaRsMU3wMpOgc1KxLyEAmrHD5aZLAD6 aJd86HtQnvrsAxQafE/e66qgMtHHxBGtEA+JumjkBvS/j7MsrrmtvJRUr60pFBELr+qBr09LM7L mgHFxrG09E6jF+q1fU2ZarB0Gy6yixyLqWFYfyOaZtlVEp80tiLXE3kGotPTYzRugdk4Qw5n4g2 +YncdG0lMq+9ePI3jLdv6SWQ26IYW9xNsHTZLx10ZlHpTToWzQwn8xWzX+ID3o+9uBkmYkFn7WB C0OuYS6yL7Yd6kHnHRJwj1xpyz3ZorlmDcICNljKumsnZR/mqyJL6BXCPnxPVU9j4S4Haf7hLv+ zyDs0iKxonXWA7A== X-Developer-Key: i=m.grzeschik@pengutronix.de; a=openpgp; fpr=957BC452CE953D7EA60CF4FC0BE9E3157A1E2C64 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: m.grzeschik@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1788210279551490385 X-GMAIL-MSGID: 1788210279551490385 This patch is adding an small python tool to forward 9pfs requests from the USB gadget to an existing 9pfs TCP server. Since currently all 9pfs servers lack support for the usb transport this tool is an useful helper to get started. Signed-off-by: Michael Grzeschik --- tools/usb/p9_fwd.py | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/tools/usb/p9_fwd.py b/tools/usb/p9_fwd.py new file mode 100755 index 0000000000000..95208df11abef --- /dev/null +++ b/tools/usb/p9_fwd.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +import argparse +import errno +import logging +import socket +import struct +import sys +import time + +import usb.core +import usb.util + + +class Forwarder: + HEXDUMP_FILTER = ( + "".join(chr(x).isprintable() and chr(x) or "." for x in range(128)) + "." * 128 + ) + + @staticmethod + def _log_hexdump(data): + if not logging.root.isEnabledFor(logging.TRACE): + return + L = 16 + for c in range(0, len(data), L): + chars = data[c : c + L] + dump = " ".join(f"{x:02x}" for x in chars) + printable = "".join(HEXDUMP_FILTER[x] for x in chars) + line = f"{c:08x} {dump:{L*3}s} |{printable:{L}s}|" + logging.root.log(logging.TRACE, "%s", line) + + def __init__(self, server): + self.stats = { + "c2s packets": 0, + "c2s bytes": 0, + "s2c packets": 0, + "s2c bytes": 0, + } + self.stats_logged = time.monotonic() + + dev = usb.core.find(idVendor=0x1D6B, idProduct=0x0109) + if dev is None: + raise ValueError("Device not found") + + logging.info(f"found device: {dev.bus}/{dev.address}") + + # dev.set_configuration() is not necessary since g_multi has only one + usb9pfs = None + # g_multi adds 9pfs as last interface + cfg = dev.get_active_configuration() + for intf in cfg: + # we have to detach the usb-storage driver from multi gadget since + # stall option could be set, which will lead to spontaneous port + # resets and our transfers will run dead + if intf.bInterfaceClass == 0x08: + if dev.is_kernel_driver_active(intf.bInterfaceNumber): + dev.detach_kernel_driver(intf.bInterfaceNumber) + + if ( + intf.bInterfaceClass == 0xFF + and intf.bInterfaceSubClass == 0xFF + and intf.bInterfaceProtocol == 0x09 + ): + usb9pfs = intf + if usb9pfs is None: + raise ValueError("Interface not found") + + logging.info(f"claiming interface:\n{usb9pfs}") + usb.util.claim_interface(dev, usb9pfs.bInterfaceNumber) + ep_out = usb.util.find_descriptor( + usb9pfs, + custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) + == usb.util.ENDPOINT_OUT, + ) + assert ep_out is not None + ep_in = usb.util.find_descriptor( + usb9pfs, + custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) + == usb.util.ENDPOINT_IN, + ) + assert ep_in is not None + logging.info(f"interface claimed") + + self.ep_out = ep_out + self.ep_in = ep_in + self.dev = dev + + # create and connect socket + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.s.connect(server) + + logging.info(f"connected to server") + + def c2s(self): + """forward a request from the USB client to the TCP server""" + data = None + while data is None: + try: + logging.log(logging.TRACE, "c2s: reading") + data = self.ep_in.read(self.ep_in.wMaxPacketSize) + except usb.core.USBTimeoutError: + logging.log(logging.TRACE, "c2s: reading timed out") + continue + except usb.core.USBError as e: + if e.errno == errno.EIO: + logging.debug("c2s: reading failed with %s, retrying", repr(e)) + time.sleep(0.5) + continue + else: + logging.error("c2s: reading failed with %s, aborting", repr(e)) + raise + size = struct.unpack(" 0 + data = data[written:] + if size % self.ep_out.wMaxPacketSize == 0: + logging.log(logging.TRACE, "sending zero length packet") + self.ep_out.write(b"") + logging.debug("s2c: forwarded %i bytes", size) + self.stats["s2c packets"] += 1 + self.stats["s2c bytes"] += size + + def log_stats(self): + logging.info("statistics:") + for k, v in self.stats.items(): + logging.info(f" {k+':':14s} {v}") + + def log_stats_interval(self, interval=5): + if (time.monotonic() - self.stats_logged) < interval: + return + + self.log_stats() + self.stats_logged = time.monotonic() + + +def main(): + parser = argparse.ArgumentParser( + description="Forward 9PFS requests from USB to TCP", + ) + + parser.add_argument( + "-s", "--server", type=str, default="127.0.0.1", help="server hostname" + ) + parser.add_argument("-p", "--port", type=int, default=564, help="server port") + parser.add_argument("-v", "--verbose", action="count", default=0) + + args = parser.parse_args() + + logging.TRACE = logging.DEBUG - 5 + logging.addLevelName(logging.TRACE, "TRACE") + + if args.verbose >= 2: + level = logging.TRACE + elif args.verbose: + level = logging.DEBUG + else: + level = logging.INFO + logging.basicConfig( + level=level, format="%(asctime)-15s %(levelname)-8s %(message)s" + ) + + f = Forwarder(server=(args.server, args.port)) + + try: + while True: + f.c2s() + f.s2c() + f.log_stats_interval() + finally: + f.log_stats() + + +if __name__ == "__main__": + main()