Skip to content

Commit

Permalink
usb: gadget: u_ether: support configuring interface names.
Browse files Browse the repository at this point in the history
This patch allows the administrator to configure the interface
name of a function using u_ether (e.g., eem, ncm, rndis).

Currently, all such interfaces, regardless of function type, are
always called usb0, usb1, etc. This makes it very cumbersome to
use more than one such type at a time, because userspace cannnot
easily tell the interfaces apart and apply the right
configuration to each one. Interface renaming in userspace based
on driver doesn't help, because the interfaces all have the same
driver. Without this patch, doing this require hacks/workarounds
such as setting fixed MAC addresses on the functions, and then
renaming by MAC address, or scraping configfs after each
interface is created to find out what it is.

Setting the interface name is done by writing to the same
"ifname" configfs attribute that reports the interface name after
the function is bound. The write must contain an interface
pattern such as "usb%d" (which will cause the net core to pick
the next available interface name starting with "usb").
This patch does not allow writing an exact interface name (as
opposed to a pattern) because if the interface already exists at
bind time, the bind will fail and the whole gadget will fail to
activate. This could be allowed in a future patch.

For compatibility with current userspace, when reading an ifname
that has not currently been set, the result is still "(unnamed
net_device)". Once a write to ifname happens, then reading ifname
will return whatever was last written.

Tested by configuring an rndis function and an ncm function on
the same gadget, and writing "rndis%d" to ifname on the rndis
function and "ncm%d" to ifname on the ncm function. When the
gadget was bound, the rndis interface was rndis0 and the ncm
interface was ncm0.

Signed-off-by: Lorenzo Colitti <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
lcolitti authored and gregkh committed Jan 15, 2021
1 parent f08fc2c commit 63d1521
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 17 deletions.
30 changes: 15 additions & 15 deletions Documentation/usb/gadget-testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ The ECM function provides these attributes in its function directory:

and after creating the functions/ecm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
The ifname can be written to if the function is not bound. A write must be an
interface pattern such as "usb%d", which will cause the net core to choose the
next free usbX interface. By default, it is set to "usb%d".

Testing the ECM function
------------------------
Expand Down Expand Up @@ -131,9 +131,9 @@ The ECM subset function provides these attributes in its function directory:

and after creating the functions/ecm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
The ifname can be written to if the function is not bound. A write must be an
interface pattern such as "usb%d", which will cause the net core to choose the
next free usbX interface. By default, it is set to "usb%d".

Testing the ECM subset function
-------------------------------
Expand Down Expand Up @@ -171,9 +171,9 @@ The EEM function provides these attributes in its function directory:

and after creating the functions/eem.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
The ifname can be written to if the function is not bound. A write must be an
interface pattern such as "usb%d", which will cause the net core to choose the
next free usbX interface. By default, it is set to "usb%d".

Testing the EEM function
------------------------
Expand Down Expand Up @@ -453,9 +453,9 @@ The NCM function provides these attributes in its function directory:

and after creating the functions/ncm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
The ifname can be written to if the function is not bound. A write must be an
interface pattern such as "usb%d", which will cause the net core to choose the
next free usbX interface. By default, it is set to "usb%d".

Testing the NCM function
------------------------
Expand Down Expand Up @@ -591,9 +591,9 @@ The RNDIS function provides these attributes in its function directory:

and after creating the functions/rndis.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
The ifname can be written to if the function is not bound. A write must be an
interface pattern such as "usb%d", which will cause the net core to choose the
next free usbX interface. By default, it is set to "usb%d".

Testing the RNDIS function
--------------------------
Expand Down
33 changes: 32 additions & 1 deletion drivers/usb/gadget/function/u_ether.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct eth_dev {

bool zlp;
bool no_skb_reserve;
bool ifname_set;
u8 host_mac[ETH_ALEN];
u8 dev_mac[ETH_ALEN];
};
Expand Down Expand Up @@ -1004,15 +1005,45 @@ EXPORT_SYMBOL_GPL(gether_get_qmult);

int gether_get_ifname(struct net_device *net, char *name, int len)
{
struct eth_dev *dev = netdev_priv(net);
int ret;

rtnl_lock();
ret = scnprintf(name, len, "%s\n", netdev_name(net));
ret = scnprintf(name, len, "%s\n",
dev->ifname_set ? net->name : netdev_name(net));
rtnl_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(gether_get_ifname);

int gether_set_ifname(struct net_device *net, const char *name, int len)
{
struct eth_dev *dev = netdev_priv(net);
char tmp[IFNAMSIZ];
const char *p;

if (name[len - 1] == '\n')
len--;

if (len >= sizeof(tmp))
return -E2BIG;

strscpy(tmp, name, len + 1);
if (!dev_valid_name(tmp))
return -EINVAL;

/* Require exactly one %d, so binding will not fail with EEXIST. */
p = strchr(name, '%');
if (!p || p[1] != 'd' || strchr(p + 2, '%'))
return -EINVAL;

strncpy(net->name, tmp, sizeof(net->name));
dev->ifname_set = true;

return 0;
}
EXPORT_SYMBOL_GPL(gether_set_ifname);

/*
* gether_cleanup - remove Ethernet-over-USB device
* Context: may sleep
Expand Down
12 changes: 12 additions & 0 deletions drivers/usb/gadget/function/u_ether.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ unsigned gether_get_qmult(struct net_device *net);
*/
int gether_get_ifname(struct net_device *net, char *name, int len);

/**
* gether_set_ifname - set an ethernet-over-usb link interface name
* @net: device representing this link
* @name: new interface name
* @len: length of @name
*
* This sets the interface name of this ethernet-over-usb link.
* A single terminating newline, if any, is ignored.
* Returns zero on success, else negative errno.
*/
int gether_set_ifname(struct net_device *net, const char *name, int len);

void gether_cleanup(struct eth_dev *dev);

/* connect/disconnect is handled by individual functions */
Expand Down
15 changes: 14 additions & 1 deletion drivers/usb/gadget/function/u_ether_configfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,20 @@ out: \
return ret; \
} \
\
CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
const char *page, size_t len)\
{ \
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret = -EBUSY; \
\
mutex_lock(&opts->lock); \
if (!opts->refcnt) \
ret = gether_set_ifname(opts->net, page, len); \
mutex_unlock(&opts->lock); \
return ret ?: len; \
} \
\
CONFIGFS_ATTR(_f_##_opts_, ifname)

#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \
static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
Expand Down

0 comments on commit 63d1521

Please sign in to comment.