From nobody Sat Feb 7 18:20:52 2026 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (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 25AC51FE45A for ; Tue, 30 Dec 2025 10:13:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089616; cv=none; b=tFgo3SBPVPKaL8mTsudiDQ7JUmBeJGPTqd6S4Rd44zHYEhwmiM+rAfYfYcLtTOgS7aRxAbe/muZVXUOPH3AMTC1A/NkYKXzY2oPii/2kmPzgD2a+pjeFh5hIlrN2XUQTr96aNorEPOUUKEC6ZUXb3x8CQGR4KmxMnOVijSGOntI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089616; c=relaxed/simple; bh=fjzdqqF7M1DPdLIRQxhjMHlueWC39nU6SrTa3Xb0wHw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mUSb/XZA0ARVqQBBr36qYyoPJeCuWKccetJwZ+fUVvGgKviLohmkyE/ipIkkiMq28yxn5QO9D/qK4uoaMC4QCzjaBLkLK83l7i2bPaJalJt236udW/S4uAZ1/r5nquyygCthvfszckc8e979UBt1W2rePN2FCJpVyRdY2ARzPjY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=hmvDQjME; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="hmvDQjME" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-7b90740249dso17304518b3a.0 for ; Tue, 30 Dec 2025 02:13:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767089613; x=1767694413; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Kk89meB0ud2XOdFPAu8jbVTDVuurvx3TMcS0DOeOUAg=; b=hmvDQjMEkbnZTeC6rYqn8OfIULc96YIaXU6yeUq9zacmrzzuelw4IJFaG4yumzsM2f nAQ/A9BnosPWORmKOmbY2cYmjmT3d5ZYrcsV6MhBWLpAjnLw/Bp8kbtQMxWMHF5dJbCR GzgITSRDMrN/AUO20jvtwjy++2oHtKck4VrwldR+YFR0TGvTsCYK323wGYIDAXTlKiQZ Bz+yo6ZYLE5YZ7/mdtJEu4foTjSbdEKhmbpU97/p8dsDwsMhJ8mk4HKK0x+tHX4ubaS0 3VaAMsCtxGT3BG4ilxuKTBEIq+/Da46FwuvPY1bFp1e/nD+PRSgzZpJFJvWHzX8GopK8 p+aA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767089613; x=1767694413; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Kk89meB0ud2XOdFPAu8jbVTDVuurvx3TMcS0DOeOUAg=; b=d7SeSbEhtvHeUse0sqlv8wxQl9dgYnwhgNuEReg/JEUE4TAFMBInJ/v5y+twXm3t5M V6+qVE0DMt42FGW1W+VDWT/hdtdX3+JHr7P7yQ+gaghoEi2OPydTpmkgOUw3k3OIoU8l SotC+LJCj7kjMwVfih/BMS82b0GehIL41cZ7bQqfEohrwrEf9BwXjh5l+8JjyMHEWszN GFTEiaSGV3TXqbEyB9htfftNmbIbFNnY/PjQsgmpqziicNX+F9T3+7ri9H5I+/JMfDk0 i0GMtF5odbnafoInyfgjvrFDqSSAseZJrrgPZHfoQ70tQEaIpE/rrawmuEHXytWVnYxb 9YzA== X-Forwarded-Encrypted: i=1; AJvYcCW3nFr5OvcFHDCaR+BGob2YyqLC/WMv20PDQisoGO90PUesMCtruG+fJvPnx9FZ2kpHh04L1kwCSZmNYTY=@vger.kernel.org X-Gm-Message-State: AOJu0YyA5eImX8V55CZYmhUwXklhOgswLlmYF3vGZEsW+rMjT13EaoxI OALuZa0577/lEAzHtXheaugIzwCn0zEgemiZCzYzEb1zMOEu/cZcNL5uo7WLfev4gR77P6+TveE 68ozsqg== X-Google-Smtp-Source: AGHT+IGWHxYFnuval1C8ZpHUVPo7+TVbRjkOJoynJUNTc5/AEHtkyMwclyiWTmgCt0O/hlFsjOwnnYlA/EE= X-Received: from pgtl20.prod.google.com ([2002:a65:6814:0:b0:c1d:27c6:5305]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:748e:b0:364:1318:caaf with SMTP id adf61e73a8af0-376aa4eaa1emr33427908637.58.1767089613485; Tue, 30 Dec 2025 02:13:33 -0800 (PST) Date: Tue, 30 Dec 2025 18:13:14 +0800 In-Reply-To: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1767089609; l=11544; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=fjzdqqF7M1DPdLIRQxhjMHlueWC39nU6SrTa3Xb0wHw=; b=neR3LoFKR7LqnFMAHLQ4VRxKimfCI0cHRZHWexdzaxnvTx4RZlY7AJGbdzAXf8OmIuspQDwhe twmSyeAAdEuBfpDY0rMX3E6KptpDLL5cpweWe1OZA8/yWY4QLClwX7j X-Mailer: b4 0.14.2 Message-ID: <20251230-ncm-refactor-v1-1-793e347bc7a7@google.com> Subject: [PATCH 1/3] usb: gadget: u_ether: add gether_opts for config caching From: Kuen-Han Tsai To: Greg Kroah-Hartman , Felipe Balbi , Prashanth K , Kyungmin Park , Andrzej Pietrasiewicz Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Currently, the net_device is allocated when the function instance is created (e.g., in ncm_alloc_inst()). While this allows userspace to configure the device early, it decouples the net_device lifecycle from the actual USB connection state (bind/unbind). The goal is to defer net_device creation to the bind callback to properly align the lifecycle with its parent gadget device. However, deferring net_device allocation would prevent userspace from configuring parameters (like interface name or MAC address) before the net_device exists. Introduce a new structure, struct gether_opts, associated with the usb_function_instance, to cache settings independently of the net_device. These settings include the interface name pattern, MAC addresses (device and host), queue multiplier, and address assignment type. New helper functions are added: - gether_setup_opts_default(): Initializes struct gether_opts with defaults, including random MAC addresses. - gether_apply_opts(): Applies the cached options from a struct gether_opts to a valid net_device. To expose these options to userspace, new configfs macros (USB_ETHER_OPTS_ITEM and USB_ETHER_OPTS_ATTR_*) are defined in u_ether_configfs.h. These attributes are part of the function instance's configfs group. This refactoring is a preparatory step. It allows the subsequent patch to safely move the net_device allocation from the instance creation phase to the bind phase without losing the ability to pre-configure the interface via configfs. Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/u_ether.c | 30 +++++ drivers/usb/gadget/function/u_ether.h | 28 ++++ drivers/usb/gadget/function/u_ether_configfs.h | 176 +++++++++++++++++++++= ++++ 3 files changed, 234 insertions(+) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/fun= ction/u_ether.c index f58590bf5e02f5f785cf5bdc287f5ce9c95e47c3..745ed2c212e3a706b0e6725731b= 42d34428f8b22 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1039,6 +1039,36 @@ int gether_set_ifname(struct net_device *net, const = char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); =20 +void gether_setup_opts_default(struct gether_opts *opts, const char *name) +{ + opts->qmult =3D QMULT_DEFAULT; + snprintf(opts->name, sizeof(opts->name), "%s%%d", name); + eth_random_addr(opts->dev_mac); + opts->addr_assign_type =3D NET_ADDR_RANDOM; + eth_random_addr(opts->host_mac); +} +EXPORT_SYMBOL_GPL(gether_setup_opts_default); + +void gether_apply_opts(struct net_device *net, struct gether_opts *opts) +{ + struct eth_dev *dev =3D netdev_priv(net); + + dev->qmult =3D opts->qmult; + + if (opts->ifname_set) { + strscpy(net->name, opts->name, sizeof(net->name)); + dev->ifname_set =3D true; + } + + memcpy(dev->host_mac, opts->host_mac, sizeof(dev->host_mac)); + + if (opts->addr_assign_type =3D=3D NET_ADDR_SET) { + memcpy(dev->dev_mac, opts->dev_mac, sizeof(dev->dev_mac)); + net->addr_assign_type =3D opts->addr_assign_type; + } +} +EXPORT_SYMBOL_GPL(gether_apply_opts); + void gether_suspend(struct gether *link) { struct eth_dev *dev =3D link->ioport; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/fun= ction/u_ether.h index 34be220cef77c49262b2098771c211326d038407..63a0240df4d749bd91c9dd67434= 06075093a3168 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -38,6 +38,31 @@ =20 struct eth_dev; =20 +/** + * struct gether_opts - Options for Ethernet gadget function instances + * @name: Pattern for the network interface name (e.g., "usb%d"). + * Used to generate the net device name. + * @qmult: Queue length multiplier for high/super speed. + * @host_mac: The MAC address to be used by the host side. + * @dev_mac: The MAC address to be used by the device side. + * @ifname_set: True if the interface name pattern has been set by userspa= ce. + * @addr_assign_type: The method used for assigning the device MAC address + * (e.g., NET_ADDR_RANDOM, NET_ADDR_SET). + * + * This structure caches network-related settings provided through configfs + * before the net_device is fully instantiated. This allows for early + * configuration while deferring net_device allocation until the function + * is bound. + */ +struct gether_opts { + char name[IFNAMSIZ]; + unsigned int qmult; + u8 host_mac[ETH_ALEN]; + u8 dev_mac[ETH_ALEN]; + bool ifname_set; + unsigned char addr_assign_type; +}; + /* * This represents the USB side of an "ethernet" link, managed by a USB * function which provides control and (maybe) framing. Two functions @@ -259,6 +284,9 @@ int gether_set_ifname(struct net_device *net, const cha= r *name, int len); =20 void gether_cleanup(struct eth_dev *dev); =20 +void gether_setup_opts_default(struct gether_opts *opts, const char *name); +void gether_apply_opts(struct net_device *net, struct gether_opts *opts); + void gether_suspend(struct gether *link); void gether_resume(struct gether *link); =20 diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/g= adget/function/u_ether_configfs.h index f558c3139ebe50d67b63a92cdc4bc0786998e23a..a3696797e074a79eafccfdf565b= 7af47485e4ce0 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -13,6 +13,12 @@ #ifndef __U_ETHER_CONFIGFS_H #define __U_ETHER_CONFIGFS_H =20 +#include +#include +#include +#include +#include + #define USB_ETHERNET_CONFIGFS_ITEM(_f_) \ static void _f_##_attr_release(struct config_item *item) \ { \ @@ -197,4 +203,174 @@ out: \ \ CONFIGFS_ATTR(_f_##_opts_, _n_) =20 +#define USB_ETHER_OPTS_ITEM(_f_) \ + static void _f_##_attr_release(struct config_item *item) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + \ + usb_put_function_instance(&opts->func_inst); \ + } \ + \ + static struct configfs_item_operations _f_##_item_ops =3D { \ + .release =3D _f_##_attr_release, \ + } + +#define USB_ETHER_OPTS_ATTR_DEV_ADDR(_f_) \ + static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \ + char *page) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + \ + guard(mutex)(&opts->lock); \ + return sysfs_emit(page, "%pM\n", opts->net_opts.dev_mac); \ + } \ + \ + static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \ + const char *page, size_t len) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + u8 new_addr[ETH_ALEN]; \ + const char *p =3D page; \ + \ + guard(mutex)(&opts->lock); \ + if (opts->refcnt) \ + return -EBUSY; \ + \ + for (int i =3D 0; i < ETH_ALEN; i++) { \ + unsigned char num; \ + if ((*p =3D=3D '.') || (*p =3D=3D ':')) \ + p++; \ + num =3D hex_to_bin(*p++) << 4; \ + num |=3D hex_to_bin(*p++); \ + new_addr[i] =3D num; \ + } \ + if (!is_valid_ether_addr(new_addr)) \ + return -EINVAL; \ + memcpy(opts->net_opts.dev_mac, new_addr, ETH_ALEN); \ + opts->net_opts.addr_assign_type =3D NET_ADDR_SET; \ + return len; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, dev_addr) + +#define USB_ETHER_OPTS_ATTR_HOST_ADDR(_f_) \ + static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \ + char *page) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + \ + guard(mutex)(&opts->lock); \ + return sysfs_emit(page, "%pM\n", opts->net_opts.host_mac); \ + } \ + \ + static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \ + const char *page, size_t len) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + u8 new_addr[ETH_ALEN]; \ + const char *p =3D page; \ + \ + guard(mutex)(&opts->lock); \ + if (opts->refcnt) \ + return -EBUSY; \ + \ + for (int i =3D 0; i < ETH_ALEN; i++) { \ + unsigned char num; \ + if ((*p =3D=3D '.') || (*p =3D=3D ':')) \ + p++; \ + num =3D hex_to_bin(*p++) << 4; \ + num |=3D hex_to_bin(*p++); \ + new_addr[i] =3D num; \ + } \ + if (!is_valid_ether_addr(new_addr)) \ + return -EINVAL; \ + memcpy(opts->net_opts.host_mac, new_addr, ETH_ALEN); \ + return len; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, host_addr) + +#define USB_ETHER_OPTS_ATTR_QMULT(_f_) \ + static ssize_t _f_##_opts_qmult_show(struct config_item *item, \ + char *page) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + \ + guard(mutex)(&opts->lock); \ + return sysfs_emit(page, "%u\n", opts->net_opts.qmult); \ + } \ + \ + static ssize_t _f_##_opts_qmult_store(struct config_item *item, \ + const char *page, size_t len) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + u32 val; \ + int ret; \ + \ + guard(mutex)(&opts->lock); \ + if (opts->refcnt) \ + return -EBUSY; \ + \ + ret =3D kstrtou32(page, 0, &val); \ + if (ret) \ + return ret; \ + \ + opts->net_opts.qmult =3D val; \ + return len; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, qmult) + +#define USB_ETHER_OPTS_ATTR_IFNAME(_f_) \ + static ssize_t _f_##_opts_ifname_show(struct config_item *item, \ + char *page) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + const char *name; \ + \ + guard(mutex)(&opts->lock); \ + rtnl_lock(); \ + if (opts->net_opts.ifname_set) \ + name =3D opts->net_opts.name; \ + else if (opts->net) \ + name =3D netdev_name(opts->net); \ + else \ + name =3D "(inactive net_device)"; \ + rtnl_unlock(); \ + return sysfs_emit(page, "%s\n", name); \ + } \ + \ + static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ + const char *page, size_t len) \ + { \ + struct f_##_f_##_opts *opts =3D to_f_##_f_##_opts(item); \ + char tmp[IFNAMSIZ]; \ + const char *p; \ + size_t c_len =3D len; \ + \ + if (c_len > 0 && page[c_len - 1] =3D=3D '\n') \ + c_len--; \ + \ + if (c_len >=3D sizeof(tmp)) \ + return -E2BIG; \ + \ + strscpy(tmp, page, c_len + 1); \ + if (!dev_valid_name(tmp)) \ + return -EINVAL; \ + \ + /* Require exactly one %d */ \ + p =3D strchr(tmp, '%'); \ + if (!p || p[1] !=3D 'd' || strchr(p + 2, '%')) \ + return -EINVAL; \ + \ + guard(mutex)(&opts->lock); \ + if (opts->refcnt) \ + return -EBUSY; \ + strscpy(opts->net_opts.name, tmp, sizeof(opts->net_opts.name)); \ + opts->net_opts.ifname_set =3D true; \ + return len; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, ifname) + #endif /* __U_ETHER_CONFIGFS_H */ --=20 2.52.0.351.gbe84eed79e-goog From nobody Sat Feb 7 18:20:52 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (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 264D4293C44 for ; Tue, 30 Dec 2025 10:13:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089618; cv=none; b=kOKnLAT0m+dYuySTmVuVh4fZ+wlrIA2A/yzI09sEOxwP/9ILwrH4yeiXv5nWoqQAFuxbdbpSoTrBwcDdn0YyPmkrFRsk6Zw9RZY776Cf1/4KH3rURBQOsExK+97MurZYoBlnz+WUPsI6vUjpmFgvmzn9XVEG0Pi/Kle8caBTx/Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089618; c=relaxed/simple; bh=bFTNHGlATa0Hla5Mbg6BP8YN6e6iG4/i1alM7w8QGgs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=UtxrxejMQXCbbgPC8uIvJztD8i1GYAg6eeJ45J83KaUkrE4dH9jv7zAg7lk9oA4k9E0w9joBs+koalHa9vdDDy4f+cx3AyylU3GxxmbK3juBQri6EsykbplhCd+DPBPaPwQlw8hGTp96Qxcl3wn5Sy/BNIkPRrKJ9hoL1hLulU0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=KUZn6Z/6; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KUZn6Z/6" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-34c21341f56so29535947a91.2 for ; Tue, 30 Dec 2025 02:13:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767089615; x=1767694415; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8jOZKIuCkqJHkqWCHRB+SikfdpIuZqSJJtfkMgy1p+g=; b=KUZn6Z/6n/DMDAGbpRLV7O70rf2a8eseHThGmhD2Xh9YFTnM2qBRmmyXPXMrDCIwwC L1qH/k/HJ2jTVjt1ZBKcu3xd3PB7uhg2PmIMbTBMSSE1sZbyD1Tan0pN3klKkJGaPykq b/Mj9xv9SYbKMx2cnFS3BQ5wDMC7Cwkj3KVus67VINbKAWyVGqk9F9jiOvY7r1k7RxYq i+gsW33rhxX6lZdlEN0PuPbPv4/aPU0W6+5CIK8I27XsSC1GNJ615AwVfFObgmFGUKSw 9jyk9zJcQHshNvTE5xlPHtAMSTRirNo+rrg/Qc7H3nOjvtZZ8VCG6q9/4pDys/NBtqvx ntbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767089615; x=1767694415; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8jOZKIuCkqJHkqWCHRB+SikfdpIuZqSJJtfkMgy1p+g=; b=B548ZpXQr6vZu6H5XX/zdJj4avV4ipLm/VOZ8zoe5+XUINqjRC6cjVLaXGGfemJ26j 89jvlDgK05ECm7DVs4fMKZkwmAsvElY80DGSYhzTbArZ2yZQRm3/govgMqe3gg64a41u lZoLLNUPcNYvf9vNsLK8oJFw/jmFnZLF9AE+D6FNzQQgnxn+DxRkA7+Qf25VHzQ3T8+3 cjBrI+2rIZpYGP0XASvkTUT4HOFXtP3ZRq1Hd3Ga2ZpnmJEbtoZLH5ONjNC/b2aogwjG iyZT3+DOCMGihQJE6Jn+AidG14RDiSBSoNv2UVlJIp8imdlSxz82WvMFzMn/ABmcWNIJ uOWg== X-Forwarded-Encrypted: i=1; AJvYcCVJtMRMoYsgd3XUBvileix/rroI045VQMQhxDBNxDthKMGLUQJ4f3B+uU7BDde3dRNPxWtEfzLR2EFIPLk=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+OCtRgXrsyQ8x13j3I4VqT2KQnJ7Ze/ctYu+2UJxz2GY8PZbk +EbZD4k7XD9VHvWJsl66maRdr39EHTTa6/Cy0xggKmzjWhk1rYZ2sklXeyt4nWaRoVfCD8y6oof zcAwNig== X-Google-Smtp-Source: AGHT+IEImhiwIBtyB9uwTQWMXDP5sO/acuizF4Z0INFLRG+6D1/NhX/w6UmGzfdzHf2E2R2GylIIrUw5nbs= X-Received: from pgag25.prod.google.com ([2002:a05:6a02:2f19:b0:c06:531d:e55b]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:32aa:b0:366:14b0:1a2f with SMTP id adf61e73a8af0-376aabfca96mr31871828637.61.1767089615374; Tue, 30 Dec 2025 02:13:35 -0800 (PST) Date: Tue, 30 Dec 2025 18:13:15 +0800 In-Reply-To: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1767089609; l=2399; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=bFTNHGlATa0Hla5Mbg6BP8YN6e6iG4/i1alM7w8QGgs=; b=sTNA+otnvqWmULvk2FmT51uy43fDZXUjva8mkEZNFZkqmy436EtKiNFWRjGUn9TJzMP5b6+SA 5Tehw6IpdSqBKlQrErEJEr9ykXOyCjMVq28RKFpz0DRHa2j76+vR9vo X-Mailer: b4 0.14.2 Message-ID: <20251230-ncm-refactor-v1-2-793e347bc7a7@google.com> Subject: [PATCH 2/3] usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device From: Kuen-Han Tsai To: Greg Kroah-Hartman , Felipe Balbi , Prashanth K , Kyungmin Park , Andrzej Pietrasiewicz Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The net_device in the u_ether framework currently requires explicit calls to unregister and free the device. Introduce gether_unregister_free_netdev() and the corresponding auto-cleanup macro. This ensures that if a net_device is registered, it is properly unregistered and the associated work queue is flushed before the memory is freed. This is a preparatory patch to simplify error handling paths in gadget drivers by removing the need for explicit goto labels for net_device cleanup. Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/u_ether.c | 15 +++++++++++++++ drivers/usb/gadget/function/u_ether.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/fun= ction/u_ether.c index 745ed2c212e3a706b0e6725731b42d34428f8b22..6c32665538cc0dcbce8e73ec8ea= 573b04c720386 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1125,6 +1125,21 @@ void gether_cleanup(struct eth_dev *dev) } EXPORT_SYMBOL_GPL(gether_cleanup); =20 +void gether_unregister_free_netdev(struct net_device *net) +{ + if (!net) + return; + + struct eth_dev *dev =3D netdev_priv(net); + + if (net->reg_state =3D=3D NETREG_REGISTERED) { + unregister_netdev(net); + flush_work(&dev->work); + } + free_netdev(net); +} +EXPORT_SYMBOL_GPL(gether_unregister_free_netdev); + /** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/fun= ction/u_ether.h index 63a0240df4d749bd91c9dd6743406075093a3168..a212a8ec5eb1b920d53fadc7a0e= 0e80e18db8ba9 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -283,6 +283,8 @@ int gether_get_ifname(struct net_device *net, char *nam= e, int len); int gether_set_ifname(struct net_device *net, const char *name, int len); =20 void gether_cleanup(struct eth_dev *dev); +void gether_unregister_free_netdev(struct net_device *net); +DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_fre= e_netdev(_T)); =20 void gether_setup_opts_default(struct gether_opts *opts, const char *name); void gether_apply_opts(struct net_device *net, struct gether_opts *opts); --=20 2.52.0.351.gbe84eed79e-goog From nobody Sat Feb 7 18:20:52 2026 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (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 F2E1E2D9EFF for ; Tue, 30 Dec 2025 10:13:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089620; cv=none; b=AP4L10WCwBmhlgnONVwPXKaSU73nNb0DGxzszhdRsBC8TO3sSfT0nqKi6XA8sIXt59drm/rf+IYBd4Pyw6W/hap4qm1HbeqvT/s6AaBapvRydU9O/f7gMaoSS9CHWoanFEiMNmb4F1Y7+dcPt+UHylSDGcnZru3pFoSS7TINumg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767089620; c=relaxed/simple; bh=V+vuLtUzxOFOzho0gfd3w8V5fzTGbDa0Otz8inB6yew=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=SrjdJqSTyOtbIGS8jBZjsdtkVV2Rz6e7T9RlpYlfsmFmZGYDVWsMdUbU9ejYN39Rheg5U2EAFtZ/QOyEXzByOunasfHbBc/YMRsdnrUq+mMf2XRmVQVt6hhu3aASVNHxUb1hp/DUUl1Ft0a7OPBjhB+4n+5ZXNPoMZgpFxWS4IQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=3Pf98mPe; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="3Pf98mPe" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-b6097ca315bso18209524a12.3 for ; Tue, 30 Dec 2025 02:13:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1767089617; x=1767694417; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=sOvss5Tw/9kk97Yc1J9wSFxhfjd/wCmusqywC0TPEkM=; b=3Pf98mPeG/KE8VSvxrx5J+K2dJlziVvvboFS/f9hm1Rpfz9wD4Q21ZF7a8/rXJjbme /ebSqIpMJjoiRAGd5bY2gXuOJ4lTIDJzBFIcLIiYgIwlhIV57ZEZVtQZgiUHEMw9py8Q aBqL68QKxyyTer1JLfUK+BQCr9zL9Rj27LSWBHT3aEjud7lARzDPYsLt/+ho7BQTbKNo KFb+KbwdH1roKkTz0T7uHpQgngSgo54tZuVvbw1Uqp+G2BbtGEa8A/h0pJIA1oHmkAkd hTn/sHciA21LtWhkB5jicTQT2m6GEeGjU3o1P3v9Ww/JFV5ajLoukUcp4q8MCyppLvN9 9Yyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767089617; x=1767694417; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sOvss5Tw/9kk97Yc1J9wSFxhfjd/wCmusqywC0TPEkM=; b=B2glyadNpO5pv1jXqAyIpNMGEn9hKOr9H5TRDyBYbMwZR74CpMCsHv/HwBqfKXdHZH 6J4UV+E0ZxyVfEm6k3vqGjNKWELJZe2vr5QiO23IGCBCEADla+A2CONpHS/PHabnJfeZ 6PIfcGtBD8yL53J5z0C2JyDd6HEq+iML5VzcVspmao3s3FfbMqEsVeJk3xVeffRo+1Fr e2pgo1LlvIi7oGmLiBU6iTYN7JdXJFp4uSP3kS5YtJdP1CAusZIR1Sg4l4k0+nv+uxpX l/iDiqXk+FM+pdlY/Tp/GhChvg1jenOSoEglGUiYAAYGTSm1kD3JLxRpBlTx62l3nLN8 dO9w== X-Forwarded-Encrypted: i=1; AJvYcCXhH8Dm7uDwnj+kpxvfWaGPqPKaaZ4jNzvNHVr3htQQCm2wX81n9vTA+McSLCq5hoLWCbQPndD44Qmo+XQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzJYScCPmWg/+5lhOstMxvleU2bhHPHQQ+Wbc+QUUPssT5UnJKS NHH0ytlrdlAmKJinU/xMyJ1Gmc8t67nW4Biw0G38zfUjGRUpU4eb9FN7jVWKrR+C5u4ueCF3hYP d0M/q+g== X-Google-Smtp-Source: AGHT+IHWCbgO2xBwg0SUc905QlZchBrMsGVFYn8nqZlrnIc+Q75J28SeBBgnAPGRmX6Nrlm8je82afclBfQ= X-Received: from pgtl20.prod.google.com ([2002:a65:6814:0:b0:c1d:27c6:5305]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:e082:b0:366:14ac:e1f5 with SMTP id adf61e73a8af0-376aa1e7fc4mr27535714637.71.1767089617218; Tue, 30 Dec 2025 02:13:37 -0800 (PST) Date: Tue, 30 Dec 2025 18:13:16 +0800 In-Reply-To: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20251230-ncm-refactor-v1-0-793e347bc7a7@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1767089609; l=11983; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=V+vuLtUzxOFOzho0gfd3w8V5fzTGbDa0Otz8inB6yew=; b=a8R520vrkG2qLB3+yBkY+hsTafAd14WNa4cpvDgqj818dX5ZNwiedJtZJgXXrswF5iWrSABzZ ubX2Z7B2EPNCxBbH0h4RIqc6vkRQ4IHg76/GoxLG8o6u3fxu2gmF8ys X-Mailer: b4 0.14.2 Message-ID: <20251230-ncm-refactor-v1-3-793e347bc7a7@google.com> Subject: [PATCH 3/3] usb: gadget: f_ncm: align net_device lifecycle with bind/unbind From: Kuen-Han Tsai To: Greg Kroah-Hartman , Felipe Balbi , Prashanth K , Kyungmin Park , Andrzej Pietrasiewicz Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Currently, the net_device is allocated in ncm_alloc_inst() and freed in ncm_free_inst(). This ties the network interface's lifetime to the configuration instance rather than the USB connection (bind/unbind). This decoupling causes issues when the USB gadget is disconnected where the underlying gadget device is removed. The net_device can outlive its parent, leading to dangling sysfs links and NULL pointer dereferences when accessing the freed gadget device. Problem 1: NULL pointer dereference on disconnect Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 Call trace: __pi_strlen+0x14/0x150 rtnl_fill_ifinfo+0x6b4/0x708 rtmsg_ifinfo_build_skb+0xd8/0x13c rtmsg_ifinfo+0x50/0xa0 __dev_notify_flags+0x4c/0x1f0 dev_change_flags+0x54/0x70 do_setlink+0x390/0xebc rtnl_newlink+0x7d0/0xac8 rtnetlink_rcv_msg+0x27c/0x410 netlink_rcv_skb+0x134/0x150 rtnetlink_rcv+0x18/0x28 netlink_unicast+0x254/0x3f0 netlink_sendmsg+0x2e0/0x3d4 Problem 2: Dangling sysfs symlinks console:/ # ls -l /sys/class/net/ncm0 lrwxrwxrwx ... /sys/class/net/ncm0 -> /sys/devices/platform/.../gadget.0/net/ncm0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/ncm0 ls: .../gadget.0/net/ncm0: No such file or directory Move the net_device allocation to ncm_bind() and deallocation to ncm_unbind(). This ensures the network interface exists only when the gadget function is actually bound to a configuration. To support pre-bind configuration (e.g., setting interface name or MAC address via configfs), cache user-provided options in f_ncm_opts using the gether_opts structure. Apply these cached settings to the net_device upon creation in ncm_bind(). Preserve the use-after-free fix from commit 6334b8e4553c ("usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport error"). Check opts->net in ncm_set_alt() and ncm_disable() to ensure gether_disconnect() runs only if a connection was established. Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface= with backward compatibility") Cc: stable@kernel.org Signed-off-by: Kuen-Han Tsai Tested-by: Ernest Van Hoecke # Aquila iMX95 --- drivers/usb/gadget/function/f_ncm.c | 128 ++++++++++++++++++--------------= ---- drivers/usb/gadget/function/u_ncm.h | 4 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/funct= ion/f_ncm.c index 0e38330271d5ac40f7f46b7e8d565c1f0d41e4b8..e23adc132f8865f6bbce6c88c8b= 5f3f06110faaa 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -83,6 +83,11 @@ static inline struct f_ncm *func_to_ncm(struct usb_funct= ion *f) return container_of(f, struct f_ncm, port.func); } =20 +static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f) +{ + return container_of(f->fi, struct f_ncm_opts, func_inst); +} + /*------------------------------------------------------------------------= -*/ =20 /* @@ -859,6 +864,7 @@ static int ncm_setup(struct usb_function *f, const stru= ct usb_ctrlrequest *ctrl) static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_ncm *ncm =3D func_to_ncm(f); + struct f_ncm_opts *opts =3D func_to_ncm_opts(f); struct usb_composite_dev *cdev =3D f->config->cdev; =20 /* Control interface has only altsetting 0 */ @@ -881,12 +887,13 @@ static int ncm_set_alt(struct usb_function *f, unsign= ed intf, unsigned alt) if (alt > 1) goto fail; =20 - if (ncm->netdev) { - DBG(cdev, "reset ncm\n"); - ncm->netdev =3D NULL; - gether_disconnect(&ncm->port); - ncm_reset_values(ncm); - } + scoped_guard(mutex, &opts->lock) + if (opts->net) { + DBG(cdev, "reset ncm\n"); + opts->net =3D NULL; + gether_disconnect(&ncm->port); + ncm_reset_values(ncm); + } =20 /* * CDC Network only sends data in non-default altsettings. @@ -919,7 +926,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned= intf, unsigned alt) net =3D gether_connect(&ncm->port); if (IS_ERR(net)) return PTR_ERR(net); - ncm->netdev =3D net; + scoped_guard(mutex, &opts->lock) + opts->net =3D net; } =20 spin_lock(&ncm->lock); @@ -1366,14 +1374,16 @@ static int ncm_unwrap_ntb(struct gether *port, static void ncm_disable(struct usb_function *f) { struct f_ncm *ncm =3D func_to_ncm(f); + struct f_ncm_opts *opts =3D func_to_ncm_opts(f); struct usb_composite_dev *cdev =3D f->config->cdev; =20 DBG(cdev, "ncm deactivated\n"); =20 - if (ncm->netdev) { - ncm->netdev =3D NULL; - gether_disconnect(&ncm->port); - } + scoped_guard(mutex, &opts->lock) + if (opts->net) { + opts->net =3D NULL; + gether_disconnect(&ncm->port); + } =20 if (ncm->notify->enabled) { usb_ep_disable(ncm->notify); @@ -1433,39 +1443,44 @@ static int ncm_bind(struct usb_configuration *c, st= ruct usb_function *f) { struct usb_composite_dev *cdev =3D c->cdev; struct f_ncm *ncm =3D func_to_ncm(f); + struct f_ncm_opts *ncm_opts =3D func_to_ncm_opts(f); struct usb_string *us; int status =3D 0; struct usb_ep *ep; - struct f_ncm_opts *ncm_opts; =20 struct usb_os_desc_table *os_desc_table __free(kfree) =3D NULL; + struct net_device *netdev __free(free_gether_netdev) =3D NULL; struct usb_request *request __free(free_usb_request) =3D NULL; =20 if (!can_support_ecm(cdev->gadget)) return -EINVAL; =20 - ncm_opts =3D container_of(f->fi, struct f_ncm_opts, func_inst); - if (cdev->use_os_string) { os_desc_table =3D kzalloc(sizeof(*os_desc_table), GFP_KERNEL); if (!os_desc_table) return -ENOMEM; } =20 - mutex_lock(&ncm_opts->lock); - gether_set_gadget(ncm_opts->net, cdev->gadget); - if (!ncm_opts->bound) { - ncm_opts->net->mtu =3D (ncm_opts->max_segment_size - ETH_HLEN); - status =3D gether_register_netdev(ncm_opts->net); + netdev =3D gether_setup_default(); + if (IS_ERR(netdev)) + return -ENOMEM; + + scoped_guard(mutex, &ncm_opts->lock) { + gether_apply_opts(netdev, &ncm_opts->net_opts); + netdev->mtu =3D ncm_opts->max_segment_size - ETH_HLEN; } - mutex_unlock(&ncm_opts->lock); =20 + gether_set_gadget(netdev, cdev->gadget); + status =3D gether_register_netdev(netdev); if (status) return status; =20 - ncm_opts->bound =3D true; - - ncm_string_defs[1].s =3D ncm->ethaddr; + /* export host's Ethernet address in CDC format */ + status =3D gether_get_host_addr_cdc(netdev, ncm->ethaddr, + sizeof(ncm->ethaddr)); + if (status < 12) + return -EINVAL; + ncm_string_defs[STRING_MAC_IDX].s =3D ncm->ethaddr; =20 us =3D usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); @@ -1563,6 +1578,8 @@ static int ncm_bind(struct usb_configuration *c, stru= ct usb_function *f) f->os_desc_n =3D 1; } ncm->notify_req =3D no_free_ptr(request); + ncm->netdev =3D no_free_ptr(netdev); + ncm->port.ioport =3D netdev_priv(ncm->netdev); =20 DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", ncm->port.in_ep->name, ncm->port.out_ep->name, @@ -1577,19 +1594,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(stru= ct config_item *item) } =20 /* f_ncm_item_ops */ -USB_ETHERNET_CONFIGFS_ITEM(ncm); +USB_ETHER_OPTS_ITEM(ncm); =20 /* f_ncm_opts_dev_addr */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm); +USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm); =20 /* f_ncm_opts_host_addr */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm); +USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm); =20 /* f_ncm_opts_qmult */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm); +USB_ETHER_OPTS_ATTR_QMULT(ncm); =20 /* f_ncm_opts_ifname */ -USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); +USB_ETHER_OPTS_ATTR_IFNAME(ncm); =20 static ssize_t ncm_opts_max_segment_size_show(struct config_item *item, char *page) @@ -1655,34 +1672,27 @@ static void ncm_free_inst(struct usb_function_insta= nce *f) struct f_ncm_opts *opts; =20 opts =3D container_of(f, struct f_ncm_opts, func_inst); - if (opts->bound) - gether_cleanup(netdev_priv(opts->net)); - else - free_netdev(opts->net); kfree(opts->ncm_interf_group); kfree(opts); } =20 static struct usb_function_instance *ncm_alloc_inst(void) { - struct f_ncm_opts *opts; + struct usb_function_instance *ret; struct usb_os_desc *descs[1]; char *names[1]; struct config_group *ncm_interf_group; =20 - opts =3D kzalloc(sizeof(*opts), GFP_KERNEL); + struct f_ncm_opts *opts __free(kfree) =3D kzalloc(sizeof(*opts), GFP_KERN= EL); if (!opts) return ERR_PTR(-ENOMEM); + + opts->net =3D NULL; opts->ncm_os_desc.ext_compat_id =3D opts->ncm_ext_compat_id; + gether_setup_opts_default(&opts->net_opts, "usb"); =20 mutex_init(&opts->lock); opts->func_inst.free_func_inst =3D ncm_free_inst; - opts->net =3D gether_setup_default(); - if (IS_ERR(opts->net)) { - struct net_device *net =3D opts->net; - kfree(opts); - return ERR_CAST(net); - } opts->max_segment_size =3D ETH_FRAME_LEN; INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); =20 @@ -1693,26 +1703,22 @@ static struct usb_function_instance *ncm_alloc_inst= (void) ncm_interf_group =3D usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, names, THIS_MODULE); - if (IS_ERR(ncm_interf_group)) { - ncm_free_inst(&opts->func_inst); + if (IS_ERR(ncm_interf_group)) return ERR_CAST(ncm_interf_group); - } opts->ncm_interf_group =3D ncm_interf_group; =20 - return &opts->func_inst; + ret =3D &opts->func_inst; + retain_and_null_ptr(opts); + return ret; } =20 static void ncm_free(struct usb_function *f) { - struct f_ncm *ncm; - struct f_ncm_opts *opts; + struct f_ncm_opts *opts =3D func_to_ncm_opts(f); =20 - ncm =3D func_to_ncm(f); - opts =3D container_of(f->fi, struct f_ncm_opts, func_inst); - kfree(ncm); - mutex_lock(&opts->lock); - opts->refcnt--; - mutex_unlock(&opts->lock); + scoped_guard(mutex, &opts->lock) + opts->refcnt--; + kfree(func_to_ncm(f)); } =20 static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) @@ -1736,13 +1742,15 @@ static void ncm_unbind(struct usb_configuration *c,= struct usb_function *f) =20 kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); + + ncm->port.ioport =3D NULL; + gether_cleanup(netdev_priv(ncm->netdev)); } =20 static struct usb_function *ncm_alloc(struct usb_function_instance *fi) { struct f_ncm *ncm; struct f_ncm_opts *opts; - int status; =20 /* allocate and initialize one new instance */ ncm =3D kzalloc(sizeof(*ncm), GFP_KERNEL); @@ -1750,22 +1758,12 @@ static struct usb_function *ncm_alloc(struct usb_fu= nction_instance *fi) return ERR_PTR(-ENOMEM); =20 opts =3D container_of(fi, struct f_ncm_opts, func_inst); - mutex_lock(&opts->lock); - opts->refcnt++; =20 - /* export host's Ethernet address in CDC format */ - status =3D gether_get_host_addr_cdc(opts->net, ncm->ethaddr, - sizeof(ncm->ethaddr)); - if (status < 12) { /* strlen("01234567890a") */ - kfree(ncm); - mutex_unlock(&opts->lock); - return ERR_PTR(-EINVAL); - } + scoped_guard(mutex, &opts->lock) + opts->refcnt++; =20 spin_lock_init(&ncm->lock); ncm_reset_values(ncm); - ncm->port.ioport =3D netdev_priv(opts->net); - mutex_unlock(&opts->lock); ncm->port.is_fixed =3D true; ncm->port.supports_multi_frame =3D true; =20 diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/funct= ion/u_ncm.h index 49ec095cdb4b6dcb330fd3149b502840312f78ec..d99330fe31e880f636615774d21= 2062952c31e43 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -15,11 +15,13 @@ =20 #include =20 +#include "u_ether.h" + struct f_ncm_opts { struct usb_function_instance func_inst; struct net_device *net; - bool bound; =20 + struct gether_opts net_opts; struct config_group *ncm_interf_group; struct usb_os_desc ncm_os_desc; char ncm_ext_compat_id[16]; --=20 2.52.0.351.gbe84eed79e-goog