Skip to content

Commit 37893bc

Browse files
Kuen-Han Tsaigregkh
authored andcommitted
Revert "usb: gadget: f_ncm: align net_device lifecycle with bind/unbind"
This reverts commit 56a512a. This commit is being reverted as part of a series-wide revert. By deferring the net_device allocation to the bind() phase, a single function instance will spawn multiple network devices if it is symlinked to multiple USB configurations. This causes regressions for userspace tools (like the postmarketOS DHCP daemon) that rely on reading the interface name (e.g., "usb0") from configfs. Currently, configfs returns the template "usb%d", causing the userspace network setup to fail. Crucially, because this patch breaks the 1:1 mapping between the function instance and the network device, this naming issue cannot simply be patched. Configfs only exposes a single 'ifname' attribute per instance, making it impossible to accurately report the actual interface name when multiple underlying network devices can exist for that single instance. All configurations tied to the same function instance are meant to share a single network device. Revert this change to restore the 1:1 mapping by allocating the network device at the instance level (alloc_inst). Reported-by: David Heidelberg <david@ixit.cz> Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ Fixes: 56a512a ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") Cc: stable <stable@kernel.org> Signed-off-by: Kuen-Han Tsai <khtsai@google.com> Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-3-ea2afbc7d9b2@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f2524c0 commit 37893bc

2 files changed

Lines changed: 66 additions & 66 deletions

File tree

drivers/usb/gadget/function/f_ncm.c

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,6 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
8383
return container_of(f, struct f_ncm, port.func);
8484
}
8585

86-
static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f)
87-
{
88-
return container_of(f->fi, struct f_ncm_opts, func_inst);
89-
}
90-
9186
/*-------------------------------------------------------------------------*/
9287

9388
/*
@@ -864,7 +859,6 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
864859
static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
865860
{
866861
struct f_ncm *ncm = func_to_ncm(f);
867-
struct f_ncm_opts *opts = func_to_ncm_opts(f);
868862
struct usb_composite_dev *cdev = f->config->cdev;
869863

870864
/* Control interface has only altsetting 0 */
@@ -887,13 +881,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
887881
if (alt > 1)
888882
goto fail;
889883

890-
scoped_guard(mutex, &opts->lock)
891-
if (opts->net) {
892-
DBG(cdev, "reset ncm\n");
893-
opts->net = NULL;
894-
gether_disconnect(&ncm->port);
895-
ncm_reset_values(ncm);
896-
}
884+
if (ncm->netdev) {
885+
DBG(cdev, "reset ncm\n");
886+
ncm->netdev = NULL;
887+
gether_disconnect(&ncm->port);
888+
ncm_reset_values(ncm);
889+
}
897890

898891
/*
899892
* CDC Network only sends data in non-default altsettings.
@@ -926,8 +919,7 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
926919
net = gether_connect(&ncm->port);
927920
if (IS_ERR(net))
928921
return PTR_ERR(net);
929-
scoped_guard(mutex, &opts->lock)
930-
opts->net = net;
922+
ncm->netdev = net;
931923
}
932924

933925
spin_lock(&ncm->lock);
@@ -1374,16 +1366,14 @@ static int ncm_unwrap_ntb(struct gether *port,
13741366
static void ncm_disable(struct usb_function *f)
13751367
{
13761368
struct f_ncm *ncm = func_to_ncm(f);
1377-
struct f_ncm_opts *opts = func_to_ncm_opts(f);
13781369
struct usb_composite_dev *cdev = f->config->cdev;
13791370

13801371
DBG(cdev, "ncm deactivated\n");
13811372

1382-
scoped_guard(mutex, &opts->lock)
1383-
if (opts->net) {
1384-
opts->net = NULL;
1385-
gether_disconnect(&ncm->port);
1386-
}
1373+
if (ncm->netdev) {
1374+
ncm->netdev = NULL;
1375+
gether_disconnect(&ncm->port);
1376+
}
13871377

13881378
if (ncm->notify->enabled) {
13891379
usb_ep_disable(ncm->notify);
@@ -1443,44 +1433,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
14431433
{
14441434
struct usb_composite_dev *cdev = c->cdev;
14451435
struct f_ncm *ncm = func_to_ncm(f);
1446-
struct f_ncm_opts *ncm_opts = func_to_ncm_opts(f);
14471436
struct usb_string *us;
14481437
int status = 0;
14491438
struct usb_ep *ep;
1439+
struct f_ncm_opts *ncm_opts;
14501440

14511441
struct usb_os_desc_table *os_desc_table __free(kfree) = NULL;
1452-
struct net_device *netdev __free(free_gether_netdev) = NULL;
14531442
struct usb_request *request __free(free_usb_request) = NULL;
14541443

14551444
if (!can_support_ecm(cdev->gadget))
14561445
return -EINVAL;
14571446

1447+
ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
1448+
14581449
if (cdev->use_os_string) {
14591450
os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL);
14601451
if (!os_desc_table)
14611452
return -ENOMEM;
14621453
}
14631454

1464-
netdev = gether_setup_default();
1465-
if (IS_ERR(netdev))
1466-
return -ENOMEM;
1467-
1468-
scoped_guard(mutex, &ncm_opts->lock) {
1469-
gether_apply_opts(netdev, &ncm_opts->net_opts);
1470-
netdev->mtu = ncm_opts->max_segment_size - ETH_HLEN;
1455+
mutex_lock(&ncm_opts->lock);
1456+
gether_set_gadget(ncm_opts->net, cdev->gadget);
1457+
if (!ncm_opts->bound) {
1458+
ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN);
1459+
status = gether_register_netdev(ncm_opts->net);
14711460
}
1461+
mutex_unlock(&ncm_opts->lock);
14721462

1473-
gether_set_gadget(netdev, cdev->gadget);
1474-
status = gether_register_netdev(netdev);
14751463
if (status)
14761464
return status;
14771465

1478-
/* export host's Ethernet address in CDC format */
1479-
status = gether_get_host_addr_cdc(netdev, ncm->ethaddr,
1480-
sizeof(ncm->ethaddr));
1481-
if (status < 12)
1482-
return -EINVAL;
1483-
ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
1466+
ncm_opts->bound = true;
1467+
1468+
ncm_string_defs[1].s = ncm->ethaddr;
14841469

14851470
us = usb_gstrings_attach(cdev, ncm_strings,
14861471
ARRAY_SIZE(ncm_string_defs));
@@ -1578,8 +1563,6 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
15781563
f->os_desc_n = 1;
15791564
}
15801565
ncm->notify_req = no_free_ptr(request);
1581-
ncm->netdev = no_free_ptr(netdev);
1582-
ncm->port.ioport = netdev_priv(ncm->netdev);
15831566

15841567
DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
15851568
ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1594,19 +1577,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
15941577
}
15951578

15961579
/* f_ncm_item_ops */
1597-
USB_ETHER_OPTS_ITEM(ncm);
1580+
USB_ETHERNET_CONFIGFS_ITEM(ncm);
15981581

15991582
/* f_ncm_opts_dev_addr */
1600-
USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm);
1583+
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm);
16011584

16021585
/* f_ncm_opts_host_addr */
1603-
USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm);
1586+
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm);
16041587

16051588
/* f_ncm_opts_qmult */
1606-
USB_ETHER_OPTS_ATTR_QMULT(ncm);
1589+
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
16071590

16081591
/* f_ncm_opts_ifname */
1609-
USB_ETHER_OPTS_ATTR_IFNAME(ncm);
1592+
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
16101593

16111594
static ssize_t ncm_opts_max_segment_size_show(struct config_item *item,
16121595
char *page)
@@ -1672,27 +1655,34 @@ static void ncm_free_inst(struct usb_function_instance *f)
16721655
struct f_ncm_opts *opts;
16731656

16741657
opts = container_of(f, struct f_ncm_opts, func_inst);
1658+
if (opts->bound)
1659+
gether_cleanup(netdev_priv(opts->net));
1660+
else
1661+
free_netdev(opts->net);
16751662
kfree(opts->ncm_interf_group);
16761663
kfree(opts);
16771664
}
16781665

16791666
static struct usb_function_instance *ncm_alloc_inst(void)
16801667
{
1681-
struct usb_function_instance *ret;
1668+
struct f_ncm_opts *opts;
16821669
struct usb_os_desc *descs[1];
16831670
char *names[1];
16841671
struct config_group *ncm_interf_group;
16851672

1686-
struct f_ncm_opts *opts __free(kfree) = kzalloc_obj(*opts);
1673+
opts = kzalloc_obj(*opts);
16871674
if (!opts)
16881675
return ERR_PTR(-ENOMEM);
1689-
1690-
opts->net = NULL;
16911676
opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;
1692-
gether_setup_opts_default(&opts->net_opts, "usb");
16931677

16941678
mutex_init(&opts->lock);
16951679
opts->func_inst.free_func_inst = ncm_free_inst;
1680+
opts->net = gether_setup_default();
1681+
if (IS_ERR(opts->net)) {
1682+
struct net_device *net = opts->net;
1683+
kfree(opts);
1684+
return ERR_CAST(net);
1685+
}
16961686
opts->max_segment_size = ETH_FRAME_LEN;
16971687
INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
16981688

@@ -1703,22 +1693,26 @@ static struct usb_function_instance *ncm_alloc_inst(void)
17031693
ncm_interf_group =
17041694
usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
17051695
names, THIS_MODULE);
1706-
if (IS_ERR(ncm_interf_group))
1696+
if (IS_ERR(ncm_interf_group)) {
1697+
ncm_free_inst(&opts->func_inst);
17071698
return ERR_CAST(ncm_interf_group);
1699+
}
17081700
opts->ncm_interf_group = ncm_interf_group;
17091701

1710-
ret = &opts->func_inst;
1711-
retain_and_null_ptr(opts);
1712-
return ret;
1702+
return &opts->func_inst;
17131703
}
17141704

17151705
static void ncm_free(struct usb_function *f)
17161706
{
1717-
struct f_ncm_opts *opts = func_to_ncm_opts(f);
1707+
struct f_ncm *ncm;
1708+
struct f_ncm_opts *opts;
17181709

1719-
scoped_guard(mutex, &opts->lock)
1720-
opts->refcnt--;
1721-
kfree(func_to_ncm(f));
1710+
ncm = func_to_ncm(f);
1711+
opts = container_of(f->fi, struct f_ncm_opts, func_inst);
1712+
kfree(ncm);
1713+
mutex_lock(&opts->lock);
1714+
opts->refcnt--;
1715+
mutex_unlock(&opts->lock);
17221716
}
17231717

17241718
static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
@@ -1742,28 +1736,36 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
17421736

17431737
kfree(ncm->notify_req->buf);
17441738
usb_ep_free_request(ncm->notify, ncm->notify_req);
1745-
1746-
ncm->port.ioport = NULL;
1747-
gether_cleanup(netdev_priv(ncm->netdev));
17481739
}
17491740

17501741
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
17511742
{
17521743
struct f_ncm *ncm;
17531744
struct f_ncm_opts *opts;
1745+
int status;
17541746

17551747
/* allocate and initialize one new instance */
17561748
ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
17571749
if (!ncm)
17581750
return ERR_PTR(-ENOMEM);
17591751

17601752
opts = container_of(fi, struct f_ncm_opts, func_inst);
1753+
mutex_lock(&opts->lock);
1754+
opts->refcnt++;
17611755

1762-
scoped_guard(mutex, &opts->lock)
1763-
opts->refcnt++;
1756+
/* export host's Ethernet address in CDC format */
1757+
status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
1758+
sizeof(ncm->ethaddr));
1759+
if (status < 12) { /* strlen("01234567890a") */
1760+
kfree(ncm);
1761+
mutex_unlock(&opts->lock);
1762+
return ERR_PTR(-EINVAL);
1763+
}
17641764

17651765
spin_lock_init(&ncm->lock);
17661766
ncm_reset_values(ncm);
1767+
ncm->port.ioport = netdev_priv(opts->net);
1768+
mutex_unlock(&opts->lock);
17671769
ncm->port.is_fixed = true;
17681770
ncm->port.supports_multi_frame = true;
17691771

drivers/usb/gadget/function/u_ncm.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515

1616
#include <linux/usb/composite.h>
1717

18-
#include "u_ether.h"
19-
2018
struct f_ncm_opts {
2119
struct usb_function_instance func_inst;
2220
struct net_device *net;
21+
bool bound;
2322

24-
struct gether_opts net_opts;
2523
struct config_group *ncm_interf_group;
2624
struct usb_os_desc ncm_os_desc;
2725
char ncm_ext_compat_id[16];

0 commit comments

Comments
 (0)