From nobody Fri Sep 25 23:53:49 2026 Received: from mail-pj1-f45.google.com (mail-pj1-f45.google.com [209.85.216.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 72A8A4908D5 for ; Mon, 7 Sep 2026 12:18:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788783512; cv=none; b=irVoG/9H93TF5rMdVT0lyWp2zdZxTUOlqfMVdQP6F5P/4hKxlAxACN0GR5FdxbMhQCZnF2U4k93ngaRLcR2P/wu8Z2TPaMtGm9wvtX0KBm64TpLjskRMu/PseMBEvhhYQ5f5osfa5eWkUZK2kI643SIzPGAtlPm/l2FeX1cn190= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788783512; c=relaxed/simple; bh=DeVxAo49YGbv7fx3J9NoLQbOb4uGHpt+SzJr/w/kcdc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lwjfNp13Hxl36lhEe82iqbCypkZ358TOAZV6pR9tn75dutEYwa5R2ZvaVDXZJ3dRZZPW+io8kAKhkIy5pxBf29wfpr2U3Vhp2sooNK1wEcXm5vEoGMmqCvSbNn8xr+K/3eqN7775k6ICnt/IZ2qxZ1MH47LVrmdUbQkWN0Rpl3Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=G39IIZ8r; arc=none smtp.client-ip=209.85.216.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="G39IIZ8r" Received: by mail-pj1-f45.google.com with SMTP id 98e67ed59e1d1-39675172593so2727009a91.2 for ; Mon, 07 Sep 2026 05:18:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788783510; x=1789388310; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=yH+H9iYsqFk1XtIUt3nOXiw8tyyJ0b7pPAD8JeW8qgM=; b=G39IIZ8r7bawHhXvI0UlyE6JJaVC3WiSVLh2UNPFjRH4EROuMh5ocsBL60Eb9vej2z Am0VszAUS6Sr6tUCONL6SVKLpuqMLhdxADWUbPgCzhdpcDTkeiI/BqVey+y1Y3ne7Zwi H8J+JLyJSw5WLzT37RX/I+UKPuhl7oDmAmDVV4WWO/PQxUmqnxqINqmxStjT1Dv4pl8G phlrFg/6/Lrv7XQHrSubo9KGLkqccI21Uesmmr6D7aGk6aPYVIcODKtEblzSdvd1DGl+ cQgQ5ZpTZezZtO+e3IJL1h+kbc7lwT+Kcn0kM1NCNEEum/hYjmmnUah2BDsQyD94PZFj pL9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788783510; x=1789388310; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=yH+H9iYsqFk1XtIUt3nOXiw8tyyJ0b7pPAD8JeW8qgM=; b=RZ+FtvqxwmQsqdYWlSNZEupiFB6Ge9qU6AfbgFviRsy0k1ClWFN7i1RP/VZQEnfG86 tTAiKvNjL29Trk5D8bxDRJyghhjDKkmEHQBMOba3PHzkSWd/CWDOL/fx6kou0A5YgLB/ Om5GgTqW3ET5PGhRdd98wYkoM7mBHR7fE3MYtK/CAhmLIsjlWH+mvEgVtpDnCJJEXoQx 89aGMHO5qlz4QWVjHUZgh6jDadXaxX9WAA/bXdcFsJ71SaYasiy1yCifo8gWUoGECcON nfo0IkOOHn3efhS0dNHjo9McF4pquW6/uX0W50w22CAauLu9yDmm/uNkBDaSTYoqkRWa v4wA== X-Forwarded-Encrypted: i=1; AKwUvBxrVl7jmwjk0BzDCJ/nyQ07vUTjoXKgmfWNzEfqd9XQCGUgQ2DxG8Q3cFy0OZbvY3eOTUEHu0k8ZfkfGpQ=@vger.kernel.org X-Gm-Message-State: AFuF++kZ2MEMTHLVDWlBLEQYCJs8JYvEPGVjRTD+o1WTYct4KDWAfG4I HSxLtY0ISuj9F7ti8VAhD+6ECXIHsKBUYgrH9KeakAHSFv3ZBifOBsTO X-Gm-Gg: AYBFou2/7RNtLFr1RQIGQ95z/eeXQyi9fDxCPOG9Zm2uxbKOzOmqYGFqkR5aif1RgUB tzWCzJtf8rRcqKpwdIpDWoIPTVI/NUGg0hUim6y/SJ8+JRMroCgGl+aAtELHx8Te6d6pPHsW88i tLbj9ev+9s9UDJHRTJVOdziTNt6EVXSk83PinDa6EsSi9RguIhH0F9/tfLEUSqmBhgVbc0S5CqN TdoGR7IkU6km4/a8x+1W9NNawOFuMu9tWJGDQgqcHILEgWXDsJ8duWtj9KeApYSHbRMpgCrp4zG lvgfKIFG7MbmBn5XRMXd75I3HbAVJNLqh5EH7ommSLESamRpgK4+nP2G2D9NUD+Aj54sFuoTOyQ LvsIvsHX5Uz3VAzRfsZu/loDYHLc5bfCMjuqEaIOUaj1REIiZH+iJD4PIYQ7kKfirXMQ2o6A4PE B/oiMtspf8xebQHceS+c4YCYbf1dfIZLIx8Rh5PD7K0maEjfuL+FPNZfRBoxD1mKxvj4A6Pdr4P rFtqaj3mtM/FWMlNtnjOtN3V8REoQ== X-Received: by 2002:a17:90b:5106:b0:37f:c22a:c188 with SMTP id 98e67ed59e1d1-39b260feb03mr33322398a91.4.1788783509576; Mon, 07 Sep 2026 05:18:29 -0700 (PDT) Received: from [10.10.15.228] (61-220-246-151.hinet-ip.hinet.net. [61.220.246.151]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-39b083e4fafsm26350223a91.1.2026.09.07.05.18.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 05:18:28 -0700 (PDT) From: Potin Lai Date: Mon, 07 Sep 2026 20:15:55 +0800 Subject: [PATCH 1/2] net: usb: cdc_ether: add NCSI passthrough support 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: quoted-printable Message-Id: <20260907-ncsi-over-usb-v1-1-6b74d2f1196c@gmail.com> References: <20260907-ncsi-over-usb-v1-0-6b74d2f1196c@gmail.com> In-Reply-To: <20260907-ncsi-over-usb-v1-0-6b74d2f1196c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Oliver Neukum , Samuel Mendoza-Jonas , Paul Fertser , Simon Horman Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Cosmo Chou , Mike Hsieh , Mik Lin , Potin Lai , Potin Lai , Adrian Ambrozewicz X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788783501; l=9154; i=potin.lai.pt@gmail.com; s=20260522; h=from:subject:message-id; bh=IS46g8ZZnzDHNyw6psl3bd746BmoiNTKXV1msvVJyZA=; b=lnZSXRtePLNu2U3kFSdVbcVwCUvptp5vJLDoUVlGiQcixI8HTa2S1rPC8PwLvR3aHB48atNjW 4FD6mPu7IVdBlJzDIcf++ubyzHb3wbYJKMrE4OphmW5GXf0b1sOLuPj X-Developer-Key: i=potin.lai.pt@gmail.com; a=ed25519; pk=j3/nMxzz1ZPpp1revghyZ8IqOnwi6RWfuxXN2XrNMRE= From: Adrian Ambrozewicz Add NCSI (Network Controller Sideband Interface) passthrough support for USB CDC Ethernet devices. This enables BMC-to-host sideband management over USB, typically used in DPU platforms where the BMC communicates with the DPU via a dedicated USB connection. Key implementation details: - Register with NCSI subsystem in ndo_open, unregister in ndo_stop - Override netdev_ops to hook open/stop for NCSI lifecycle management - Keep carrier always on while interface is up, as NCSI control traffic shares the USB data path (unlike PHY-based drivers) - Ignore CDC status notifications since NCSI manages link state - Forward VLAN operations to NCSI subsystem The symmetric open/stop lifecycle is critical for USB drivers: open() -> ncsi_register_dev() + ncsi_start_dev() stop() -> ncsi_stop_dev() + ncsi_unregister_dev() This ensures NCSI packet handlers are removed BEFORE unregister_netdev() checks for them during USB disconnect, avoiding kernel crashes. Unlike platform drivers where unbind() runs before unregister_netdev(), USB drivers have the opposite order: usbnet_disconnect() -> unregister_netdev() -> unbind() Placing NCSI cleanup in unbind() would be too late. Supported hardware: NVIDIA DPU USB CDC Ethernet (VID:PID 0955:cf11) Signed-off-by: Adrian Ambrozewicz Signed-off-by: Potin Lai --- drivers/net/usb/Kconfig | 20 +++++ drivers/net/usb/cdc_ether.c | 190 ++++++++++++++++++++++++++++++++++++++++= +++- 2 files changed, 209 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 52a5c0922c79..00757392128f 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -241,6 +241,26 @@ config USB_NET_CDCETHER IEEE 802 "local assignment" bit is set in the address, a "usbX" name is used instead. =20 +config USB_NET_CDCETHER_NCSI + bool "NCSI passthrough support for CDC Ethernet" + depends on USB_NET_CDCETHER + depends on NET_NCSI + help + This option enables NCSI (Network Controller Sideband Interface) + passthrough support for specific USB CDC Ethernet devices. + + NCSI allows a BMC (Baseboard Management Controller) to share a + network interface with the host system for out-of-band management. + This is typically used in DPU (Data Processing Unit) platforms + where the BMC communicates with the DPU via a dedicated USB + connection. + + Currently supported devices: + * NVIDIA BlueField DPU (VID:PID 0955:cf11) + + Say Y here if you have a system with USB-based NCSI connectivity + between BMC and host. If unsure, say N. + config USB_NET_CDC_EEM tristate "CDC EEM support" depends on USB_USBNET diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index a0a5740590b9..e5d3924e6a2e 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -538,6 +538,168 @@ static const struct driver_info cdc_info =3D { .manage_power =3D usbnet_manage_power, }; =20 +/* + * NCSI passthrough support for USB CDC Ethernet devices. + * + * Enables BMC-to-host sideband management over USB, typically used in + * DPU (Data Processing Unit) platforms where the BMC communicates with + * the DPU via a dedicated USB connection. + */ +#ifdef CONFIG_USB_NET_CDCETHER_NCSI +#include + +/* NCSI operates at 100 Mbps */ +#define NCSI_SPEED_BPS (100 * 1000000) + +struct cdc_ncsi_priv { + struct ncsi_dev *ndev; + struct net_device_ops netdev_ops; + const struct net_device_ops *orig_netdev_ops; +}; + +static int cdc_ncsi_open(struct net_device *net); +static int cdc_ncsi_stop(struct net_device *net); + +static void cdc_ncsi_handler(struct ncsi_dev *nd) +{ + if (unlikely(nd->state !=3D ncsi_dev_state_functional)) + return; + + netdev_dbg(nd->dev, "NCSI interface %s\n", + nd->link_up ? "up" : "down"); + + /* Don't toggle carrier here - it must stay on for NCSI to + * communicate over USB. Carrier was enabled in cdc_ncsi_open(). + */ +} + +static int cdc_ncsi_bind(struct usbnet *dev, struct usb_interface *intf) +{ + struct cdc_ncsi_priv *priv; + struct cdc_state *info; + int status; + + status =3D usbnet_ether_cdc_bind(dev, intf); + if (status < 0) + return status; + + info =3D (void *)&dev->data; + status =3D usbnet_get_ethernet_addr(dev, info->ether->iMACAddress); + if (status < 0) + goto err_unbind; + + priv =3D kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + status =3D -ENOMEM; + goto err_unbind; + } + + dev->driver_priv =3D priv; + + /* Override netdev_ops for NCSI lifecycle management */ + priv->orig_netdev_ops =3D dev->net->netdev_ops; + priv->netdev_ops =3D *dev->net->netdev_ops; + priv->netdev_ops.ndo_open =3D cdc_ncsi_open; + priv->netdev_ops.ndo_stop =3D cdc_ncsi_stop; + priv->netdev_ops.ndo_vlan_rx_add_vid =3D ncsi_vlan_rx_add_vid; + priv->netdev_ops.ndo_vlan_rx_kill_vid =3D ncsi_vlan_rx_kill_vid; + dev->net->netdev_ops =3D &priv->netdev_ops; + + dev->net->hw_features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; + dev->net->features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; + + dev->rx_speed =3D NCSI_SPEED_BPS; + dev->tx_speed =3D NCSI_SPEED_BPS; + + netdev_info(dev->net, "NCSI passthrough enabled\n"); + return 0; + +err_unbind: + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver_of(intf), info->data); + return status; +} + +static void cdc_ncsi_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct cdc_ncsi_priv *priv =3D dev->driver_priv; + + if (priv) { + /* Restore original netdev_ops before freeing priv */ + dev->net->netdev_ops =3D priv->orig_netdev_ops; + kfree(priv); + dev->driver_priv =3D NULL; + } + + usbnet_cdc_unbind(dev, intf); +} + +static int cdc_ncsi_open(struct net_device *net) +{ + struct usbnet *dev =3D netdev_priv(net); + struct cdc_ncsi_priv *priv =3D dev->driver_priv; + int ret; + + ret =3D usbnet_open(net); + if (ret) + return ret; + + priv->ndev =3D ncsi_register_dev(net, cdc_ncsi_handler); + if (!priv->ndev) { + netdev_err(net, "failed to register NCSI device\n"); + usbnet_stop(net); + return -ENODEV; + } + + /* Carrier must stay on for NCSI to transmit/receive its control + * packets over USB. Unlike PHY-based drivers, we cannot toggle + * carrier based on NCSI link state without breaking USB I/O. + */ + netif_carrier_on(net); + ret =3D ncsi_start_dev(priv->ndev); + if (ret) { + netdev_err(net, "failed to start NCSI: %d\n", ret); + ncsi_unregister_dev(priv->ndev); + priv->ndev =3D NULL; + netif_carrier_off(net); + usbnet_stop(net); + return ret; + } + + return 0; +} + +static int cdc_ncsi_stop(struct net_device *net) +{ + struct usbnet *dev =3D netdev_priv(net); + struct cdc_ncsi_priv *priv =3D dev->driver_priv; + + if (priv->ndev) { + ncsi_stop_dev(priv->ndev); + ncsi_unregister_dev(priv->ndev); + priv->ndev =3D NULL; + } + + netif_carrier_off(net); + return usbnet_stop(net); +} + +static void cdc_ncsi_status(struct usbnet *dev, struct urb *urb) +{ + /* NCSI manages link state, ignore CDC status notifications */ +} + +static const struct driver_info cdc_ncsi_info =3D { + .description =3D "CDC Ethernet Device (NCSI)", + .flags =3D FLAG_ETHER | FLAG_POINTTOPOINT, + .bind =3D cdc_ncsi_bind, + .unbind =3D cdc_ncsi_unbind, + .status =3D cdc_ncsi_status, + .set_rx_mode =3D usbnet_cdc_update_filter, + .manage_power =3D usbnet_manage_power, +}; +#endif /* CONFIG_USB_NET_CDCETHER_NCSI */ + static const struct driver_info zte_cdc_info =3D { .description =3D "ZTE CDC Ethernet Device", .flags =3D FLAG_ETHER | FLAG_POINTTOPOINT, @@ -946,7 +1108,33 @@ static const struct usb_device_id products[] =3D { USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info =3D (unsigned long)&wwan_info, -}, { +}, +/* + * NCSI passthrough support. + * + * This implementation enables NCSI unconditionally for matching VID/PID. + * Per-driver integration is required because the NCSI subsystem mandates + * explicit lifecycle calls (ncsi_register/start/stop/unregister_dev). + * + * OPEN QUESTION: An alternative approach using DTS "use-ncsi" property + * for conditional enablement was considered. This is viable only when + * USB topology is fixed and known at build time. Whether DPU deployments + * have fixed topologies remains to be determined. Note that DTS-based + * control would still require per-driver integration. + * + * A future generic solution could eliminate per-driver modifications by + * extending the NCSI subsystem to hook netdev lifecycle events directly, + * with interface selection configured via DTS or sysfs. + */ +#ifdef CONFIG_USB_NET_CDCETHER_NCSI +{ + USB_DEVICE_AND_INTERFACE_INFO(NVIDIA_VENDOR_ID, 0xcf11, + USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info =3D (unsigned long)&cdc_ncsi_info, +}, +#endif /* CONFIG_USB_NET_CDCETHER_NCSI */ +{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info =3D (unsigned long) &cdc_info, --=20 2.52.0 From nobody Fri Sep 25 23:53:49 2026 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54B08492530 for ; Mon, 7 Sep 2026 12:18:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788783515; cv=none; b=TakJNtqCvLpRlgKbRlxoAc7ZnWtlErcg3x8D0a5m5/IbSDNtMn0xeuT05y1cGnRJHNqqEj5SeRvTkPZf6aaq9pUYDzIbmJ4sph6VJH6DkPxUZK5WzyInQ30G0pxPvJhfkxs5z7T+jpUmHxPkcWywmRRKgbmX+nRjEcy5QE1IRbM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788783515; c=relaxed/simple; bh=CcasSbXAfa4DfM6hENk/1QhC0O7DnAUmCxYFdyKRN14=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eXxI23/p/eBI0lnJ9IwWGGmjUZTuywOdT4lRD1SygQy5+ycWWeTjQGedX1D9NaKKOVbCISzZ2FE3FsnUZ8vxZaB3iDJz0ZwNlXjzYsVkH4lozQuAzpuYVfG5gsOSQ4sIqqVPVoKvOQ/6c2J3CwRLz/+Xde2rluscLP4Akwdaw7Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=YnkJY2oL; arc=none smtp.client-ip=209.85.216.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YnkJY2oL" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-3966791a6eeso4176929a91.3 for ; Mon, 07 Sep 2026 05:18:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788783514; x=1789388314; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=MCqNc5TOpRye2fp14VARg3h/zUv18AYnd+sTa9Mn2uA=; b=YnkJY2oLuMqM9o12sp/S5QKUkjywE3vLVlB+rT8j0y/z144ciL+UtPcWaPWATPtHBH /85OidxIT33WofdU4nCIbAyJ63LO5tnDAHGPC13ENv3uEPrPWXlxbC9sk+TWr4DeKlid H1q0vTntaqrk9W0vH6VzxY9x4h5BRIh4Qd6T0rHubuGb8LbkuYQU/+BuzS/BV3fmB+PR ZUT2qyD5LZNwGrfyoJxyAzMshaOy4Ru57D3klElNo+JAipLf4McGU0k2H4EET09raGS/ VdH87gvUWbiJstZk3f6gHjRWzPOlfE4fwXw9gmSER5c7B+cCmu3S1R5w2B16fKpNKnS9 t9+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788783514; x=1789388314; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=MCqNc5TOpRye2fp14VARg3h/zUv18AYnd+sTa9Mn2uA=; b=TtE4Y5dalW+CTXlnLZUoUm+WTUklBI3H+GeLKHjEWEFTMvY/WVjYFQK3LGFPG/nJR0 dvlz5rlX2NRM1o6kQ1iztd1bDDlQkMtjY9H5DdFuYTo8R+FcZ0p5thvkw/jNa6yVzy/P udSSzM6GepcbESFz/eTN2/abb/3z28GHYo9jZ7uTLC7TxA1TLXG7iLX83kJaAn5qdzvD o7sSJ+JqoBd+yxB9zL1ZbCJpWE9ZPciu9k5gKQueUB/ryr0cWzoB3zbfF1rSvOJ8kFn5 Jm0wNApDas83LN9ITDcCr4u6X3UH0vqgsjEm//1qSgVzBTfM1C7q1PLSXCQWbPiZuWgp 9S6A== X-Forwarded-Encrypted: i=1; AKwUvBy3ke1EifR3UliYK/34WlKgc633OBb+JbDjWywSh0GBwFl22gFdo0qDTsdD/H+IYC6S6Yen82dWUj/WpFY=@vger.kernel.org X-Gm-Message-State: AFuF++lmtLvkB297qLkHWrAbZA7bcq221X7qPfdZ8RcswfhHE4ou0xSd 04V3mMwRN+z02Z99tmH2reaJUbDCS6jK0MFwvwY+tQ8nR2Boc3CShUmN X-Gm-Gg: AYBFou2Xy7ax7rBbbIbLs/K3zDzzQb+IE8E3+S4maENIhyTkv2JPDyX6m/QVgnLi4AD BivP4BEZHD1rEW9hVM6JV/oj9N0zT5E2b7baGCdfz1KJRHvwJt+XLgScYgEqzCH9dvCaEi5jMf+ F7YXl4GcPufI7N7ncuKyGISoLuI4CnDr5lfKmZl/7IEr0vlXwud6ivfGyItgQgFOjQ4tlULJgPu /9KaSDv9IvV+FxWB9QQAav0JZEn9iRecoTedTYs2Tf2c1vYpQqry42rvEDSGhul18y3FaF9djS7 1YTpUqeO1B6ll996YzdXEZJstElmYi3THJcdFArWYQmKSyo/7thcJHZ+VsLyg/D7YXeVcbzgLbS 3J13DvRsmoxBkEVw+i1dhVLDkBNjuOaSliHGkP6om14JrDRdQDFmp5ntPywI7MigGlEskF/Cc3I fFoRmtGUfdBERQw5Y+ny6qYdyrVTQPpNQ/w3M7j6MYLxMOSxjBljQ/tfmwasfSVGKiaJv2R9iwo 6zzIVCm85Ehbj2tRWaMCdrS8fn4+ZHRk+90NZIT X-Received: by 2002:a17:90a:164f:b0:39b:3510:49e7 with SMTP id 98e67ed59e1d1-39b35105b52mr17653094a91.0.1788783513565; Mon, 07 Sep 2026 05:18:33 -0700 (PDT) Received: from [10.10.15.228] (61-220-246-151.hinet-ip.hinet.net. [61.220.246.151]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-39b083e4fafsm26350223a91.1.2026.09.07.05.18.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 05:18:33 -0700 (PDT) From: Potin Lai Date: Mon, 07 Sep 2026 20:15:56 +0800 Subject: [PATCH 2/2] net/ncsi: fix use-after-free in ncsi_unregister_dev() 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: quoted-printable Message-Id: <20260907-ncsi-over-usb-v1-2-6b74d2f1196c@gmail.com> References: <20260907-ncsi-over-usb-v1-0-6b74d2f1196c@gmail.com> In-Reply-To: <20260907-ncsi-over-usb-v1-0-6b74d2f1196c@gmail.com> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Oliver Neukum , Samuel Mendoza-Jonas , Paul Fertser , Simon Horman Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Cosmo Chou , Mike Hsieh , Mik Lin , Potin Lai , Potin Lai , Adrian Ambrozewicz X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788783501; l=3955; i=potin.lai.pt@gmail.com; s=20260522; h=from:subject:message-id; bh=yZHToefB2J4gDdcqtGX3KbgxAzfg+MKJFuVi4HEdB4w=; b=ZDRSnx+CLa9vQppAxhLW4mwzQ0C64Hmz8qxYoj2NL0/N3XCxp+UUhT+4K8pCUYJml0ZkQZs1T phe+xI6OehLCfDrOrAB3pGWlKr8DLU/0B3zpOAadiwGvJm31hoTPGhs X-Developer-Key: i=potin.lai.pt@gmail.com; a=ed25519; pk=j3/nMxzz1ZPpp1revghyZ8IqOnwi6RWfuxXN2XrNMRE= From: Adrian Ambrozewicz ncsi_unregister_dev() frees the ncsi_dev_priv structure while timers and workqueue may still be accessing it, causing use-after-free. The problem involves two async mechanisms: 1. Request timers (ncsi_request_timeout) - fire when NCSI responses are not received in time 2. Workqueue (ncsi_dev_work) - processes NCSI state machine These can cascade: timer handlers call ncsi_free_request() which may call schedule_work(), and work can send commands that arm new timers. The fix adds proper synchronization before kfree(): dev_remove_pack() - stop packet reception del_timer_sync() x 256 - cancel all request timers cancel_work_sync() - wait for workqueue to complete kfree(ndp) Order matters: timers must be cancelled before work because timer handlers may schedule new work via ncsi_free_request(). Note: ncsi_dev_work() is non-blocking - it sends a command, arms a timer, and returns immediately. It does not wait for timer completion. The timer firing later triggers schedule_work() for the next state. So cancel_work_sync() will not hang waiting for cancelled timers. This relies on ncsi_stop_dev() being called first (guaranteed by the network device lifecycle). ncsi_stop_dev() sets state to ncsi_dev_state_functional, which causes ncsi_dev_work() to exit immediately without sending commands or arming timers. This breaks the timer<->work cycle and ensures the synchronization terminates. Timeline showing the race (without fix): CPU 0 (unregister) CPU 1 (async) ------------------ ------------- ncsi_unregister_dev() dev_remove_pack() ncsi_request_timeout() ncsi_free_request() schedule_work() kfree(ndp) ncsi_dev_work() ndp->... <- UAF! With fix: CPU 0 (unregister) CPU 1 (async) ------------------ ------------- ncsi_unregister_dev() dev_remove_pack() del_timer_sync() x 256 <- waits for timer handlers ncsi_request_timeout() ncsi_free_request() schedule_work() cancel_work_sync() <- waits for work ncsi_dev_work() state=3D0x100, exits immediately kfree(ndp) <- safe Signed-off-by: Adrian Ambrozewicz Signed-off-by: Potin Lai --- net/ncsi/ncsi-manage.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c index 54d0df0a9efe..dc5f2a76a0a5 100644 --- a/net/ncsi/ncsi-manage.c +++ b/net/ncsi/ncsi-manage.c @@ -1957,9 +1957,28 @@ void ncsi_unregister_dev(struct ncsi_dev *nd) struct ncsi_dev_priv *ndp =3D TO_NCSI_DEV_PRIV(nd); struct ncsi_package *np, *tmp; unsigned long flags; + int i; =20 dev_remove_pack(&ndp->ptype); =20 + /* + * Synchronize with async operations before freeing ndp. + * + * Note: The caller must have called ncsi_stop_dev() first, which + * sets nd->state to ncsi_dev_state_functional (0x100). This causes + * any running or scheduled ncsi_dev_work() to exit immediately + * without sending commands or arming new timers, breaking the + * potential cycle of: work -> arm timer -> timer -> schedule work. + * + * Order matters: + * 1. del_timer_sync() - cancel timers, handlers may schedule work + * 2. cancel_work_sync() - cancel work scheduled by timer handlers + */ + for (i =3D 0; i < ARRAY_SIZE(ndp->requests); i++) + del_timer_sync(&ndp->requests[i].timer); + + cancel_work_sync(&ndp->work); + list_for_each_entry_safe(np, tmp, &ndp->packages, node) ncsi_remove_package(np); =20 --=20 2.52.0