Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: u_ether: support configuring interface names.

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 <lorenzo@google.com>
Link: https://lore.kernel.org/r/20210113234222.3272933-1-lorenzo@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Lorenzo Colitti and committed by
Greg Kroah-Hartman
63d15214 f08fc2c3

+73 -17
+15 -15
Documentation/usb/gadget-testing.rst
··· 91 91 92 92 and after creating the functions/ecm.<instance name> they contain default 93 93 values: qmult is 5, dev_addr and host_addr are randomly selected. 94 - Except for ifname they can be written to until the function is linked to a 95 - configuration. The ifname is read-only and contains the name of the interface 96 - which was assigned by the net core, e. g. usb0. 94 + The ifname can be written to if the function is not bound. A write must be an 95 + interface pattern such as "usb%d", which will cause the net core to choose the 96 + next free usbX interface. By default, it is set to "usb%d". 97 97 98 98 Testing the ECM function 99 99 ------------------------ ··· 131 131 132 132 and after creating the functions/ecm.<instance name> they contain default 133 133 values: qmult is 5, dev_addr and host_addr are randomly selected. 134 - Except for ifname they can be written to until the function is linked to a 135 - configuration. The ifname is read-only and contains the name of the interface 136 - which was assigned by the net core, e. g. usb0. 134 + The ifname can be written to if the function is not bound. A write must be an 135 + interface pattern such as "usb%d", which will cause the net core to choose the 136 + next free usbX interface. By default, it is set to "usb%d". 137 137 138 138 Testing the ECM subset function 139 139 ------------------------------- ··· 171 171 172 172 and after creating the functions/eem.<instance name> they contain default 173 173 values: qmult is 5, dev_addr and host_addr are randomly selected. 174 - Except for ifname they can be written to until the function is linked to a 175 - configuration. The ifname is read-only and contains the name of the interface 176 - which was assigned by the net core, e. g. usb0. 174 + The ifname can be written to if the function is not bound. A write must be an 175 + interface pattern such as "usb%d", which will cause the net core to choose the 176 + next free usbX interface. By default, it is set to "usb%d". 177 177 178 178 Testing the EEM function 179 179 ------------------------ ··· 453 453 454 454 and after creating the functions/ncm.<instance name> they contain default 455 455 values: qmult is 5, dev_addr and host_addr are randomly selected. 456 - Except for ifname they can be written to until the function is linked to a 457 - configuration. The ifname is read-only and contains the name of the interface 458 - which was assigned by the net core, e. g. usb0. 456 + The ifname can be written to if the function is not bound. A write must be an 457 + interface pattern such as "usb%d", which will cause the net core to choose the 458 + next free usbX interface. By default, it is set to "usb%d". 459 459 460 460 Testing the NCM function 461 461 ------------------------ ··· 591 591 592 592 and after creating the functions/rndis.<instance name> they contain default 593 593 values: qmult is 5, dev_addr and host_addr are randomly selected. 594 - Except for ifname they can be written to until the function is linked to a 595 - configuration. The ifname is read-only and contains the name of the interface 596 - which was assigned by the net core, e. g. usb0. 594 + The ifname can be written to if the function is not bound. A write must be an 595 + interface pattern such as "usb%d", which will cause the net core to choose the 596 + next free usbX interface. By default, it is set to "usb%d". 597 597 598 598 Testing the RNDIS function 599 599 --------------------------
+32 -1
drivers/usb/gadget/function/u_ether.c
··· 80 80 81 81 bool zlp; 82 82 bool no_skb_reserve; 83 + bool ifname_set; 83 84 u8 host_mac[ETH_ALEN]; 84 85 u8 dev_mac[ETH_ALEN]; 85 86 }; ··· 1005 1004 1006 1005 int gether_get_ifname(struct net_device *net, char *name, int len) 1007 1006 { 1007 + struct eth_dev *dev = netdev_priv(net); 1008 1008 int ret; 1009 1009 1010 1010 rtnl_lock(); 1011 - ret = scnprintf(name, len, "%s\n", netdev_name(net)); 1011 + ret = scnprintf(name, len, "%s\n", 1012 + dev->ifname_set ? net->name : netdev_name(net)); 1012 1013 rtnl_unlock(); 1013 1014 return ret; 1014 1015 } 1015 1016 EXPORT_SYMBOL_GPL(gether_get_ifname); 1017 + 1018 + int gether_set_ifname(struct net_device *net, const char *name, int len) 1019 + { 1020 + struct eth_dev *dev = netdev_priv(net); 1021 + char tmp[IFNAMSIZ]; 1022 + const char *p; 1023 + 1024 + if (name[len - 1] == '\n') 1025 + len--; 1026 + 1027 + if (len >= sizeof(tmp)) 1028 + return -E2BIG; 1029 + 1030 + strscpy(tmp, name, len + 1); 1031 + if (!dev_valid_name(tmp)) 1032 + return -EINVAL; 1033 + 1034 + /* Require exactly one %d, so binding will not fail with EEXIST. */ 1035 + p = strchr(name, '%'); 1036 + if (!p || p[1] != 'd' || strchr(p + 2, '%')) 1037 + return -EINVAL; 1038 + 1039 + strncpy(net->name, tmp, sizeof(net->name)); 1040 + dev->ifname_set = true; 1041 + 1042 + return 0; 1043 + } 1044 + EXPORT_SYMBOL_GPL(gether_set_ifname); 1016 1045 1017 1046 /* 1018 1047 * gether_cleanup - remove Ethernet-over-USB device
+12
drivers/usb/gadget/function/u_ether.h
··· 244 244 */ 245 245 int gether_get_ifname(struct net_device *net, char *name, int len); 246 246 247 + /** 248 + * gether_set_ifname - set an ethernet-over-usb link interface name 249 + * @net: device representing this link 250 + * @name: new interface name 251 + * @len: length of @name 252 + * 253 + * This sets the interface name of this ethernet-over-usb link. 254 + * A single terminating newline, if any, is ignored. 255 + * Returns zero on success, else negative errno. 256 + */ 257 + int gether_set_ifname(struct net_device *net, const char *name, int len); 258 + 247 259 void gether_cleanup(struct eth_dev *dev); 248 260 249 261 /* connect/disconnect is handled by individual functions */
+14 -1
drivers/usb/gadget/function/u_ether_configfs.h
··· 148 148 return ret; \ 149 149 } \ 150 150 \ 151 - CONFIGFS_ATTR_RO(_f_##_opts_, ifname) 151 + static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ 152 + const char *page, size_t len)\ 153 + { \ 154 + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ 155 + int ret = -EBUSY; \ 156 + \ 157 + mutex_lock(&opts->lock); \ 158 + if (!opts->refcnt) \ 159 + ret = gether_set_ifname(opts->net, page, len); \ 160 + mutex_unlock(&opts->lock); \ 161 + return ret ?: len; \ 162 + } \ 163 + \ 164 + CONFIGFS_ATTR(_f_##_opts_, ifname) 152 165 153 166 #define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ 154 167 static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\