Received: by 2002:a05:7412:8d09:b0:fa:4c10:6cad with SMTP id bj9csp189270rdb; Mon, 15 Jan 2024 17:56:24 -0800 (PST) X-Google-Smtp-Source: AGHT+IH2mVnOArckMBn5owgv74WujOkQeoL4yyhUxpvkBIY9UP1kTSvAdJZdDZD9zVH/NpxJaH8N X-Received: by 2002:a17:903:487:b0:1d4:bce0:875d with SMTP id jj7-20020a170903048700b001d4bce0875dmr6731520plb.128.1705370183774; Mon, 15 Jan 2024 17:56:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705370183; cv=none; d=google.com; s=arc-20160816; b=tVf/8O3oWG5Bi+M9Q7zH5F1h8dM7r9mIit2g5tKsHvgwAR0QAfMaXMBxmUb1V/lwNJ gKq6pkQmT9NA8CaRkCQQNm7VUOl/s7NHrgAs6TFJKNSuDDXHNiezRqfAIfwq4itDtmhX /JcFr8YlkaGuYwl48N+kgsNGEuM0nfZH+iwz6Fy3C2nQuEUgL8A7Bk3PBkUHuuCxb70u nrSZYDnSd9+5uP5kNSJUkRFBUMMkXk7oZny1YCTHJ41JekmfhCJpr8idOpuuQ8L2jFIJ IEmhkpTfYKuV3o00YO/s7hN7A1aw/JJpzltOYgTeuF0gCfiwxnYf6onEfKOiiXTxsTc+ aoNw== 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-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-26914-linux.lists.archive=gmail.com@vger.kernel.org" Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [139.178.88.99]) by mx.google.com with ESMTPS id kk8-20020a170903070800b001d4bc8b662asi9636166plb.230.2024.01.15.17.56.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Jan 2024 17:56:23 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-26914-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) client-ip=139.178.88.99; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel+bounces-26914-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-26914-linux.lists.archive=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 sv.mirrors.kernel.org (Postfix) with ESMTPS id 6F7A32837AB for ; Tue, 16 Jan 2024 01:56:23 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4D14912B89; Tue, 16 Jan 2024 01:49:57 +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 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit 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 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() -- 2.39.2