1

I am in the process of developing a bash script which automates the addition of a USB wifi dongle to a virtual machine (QEmu/KVM virtualization) and therefore to add a wifi key to a VM.

[edit]This VM is for the moment with Debian Buster distro[/edit]

From the host when I plug in my TP-Link TL-WN823N USB dongle, the following interface is added :

user@host:~$ ip -o link | grep wlx
57: wlx123456789012: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 2a:51:d5:12:34:56 brd ff:ff:ff:ff:ff:ff

When I list the USB devices I get :

user@host:~$ lsusb | grep TP-Link
Bus 002 Device 009: ID 2357:0109 TP-Link TL WN823N RTL8192EU

It is therefore identified by the wlx123456789012 interface, its vendor:product ID is 2357:0109 and is device #9 of USB bus #2.*

How to determine for sure vendor:product ID when we only know the name of the interface ?

@meuh suggestion

user@host:~$ ls --format=commas /sys/class/net/wlx123456789012/device
authorized, bAlternateSetting, bInterfaceClass, bInterfaceNumber,
bInterfaceProtocol, bInterfaceSubClass, bNumEndpoints, driver,
ep_01, ep_02, ep_03, ep_04, ep_05, ep_06, ep_81, ieee80211, leds,
modalias, net, power, subsystem, supports_autosuspend, uevent

So no vendor nor device file directly in this location (according to him it would be due to the fact that its test concerns an on-board wifi)

But that inspired me, so I tried :

    user@host:~$ grep -iEr "2357|0109" /sys/class/net/wlx123456789012/device
...
/sys/class/net/wlx123456789012/device/modalias:usb:v2357p0109d0101dc00dsc00dp00icFFiscFFipFFin00
/sys/class/net/wlx123456789012/device/uevent:PRODUCT=2357/0109/101
/sys/class/net/wlx123456789012/device/uevent:MODALIAS=usb:v2357p0109d0101dc00dsc00dp00icFFiscFFipFFin00

So in /sys/class/net/wlx123456789012/device, there are :

modalias : usb:v2357p0109d0101dc00dsc00dp00icFFiscFFipFFin00

uevent : PRODUCT=2357/0109/101

So I found traces but the fact that @meuh gives me another localization makes me doubt that the solution (especially if I change the version of the distro or just the distro)

@Tom Yan suggestion

user@host:~$ udevadm info /sys/class/net/wlx123456789012 \
 | sort -r | awk '/ID_(VENDOR|MODEL)_ID/'
E: ID_VENDOR_ID=2357
E: ID_MODEL_ID=0109

Notas : here MODEL is used instead of PRODUCT ; sort -r is used to sort VENDOR line prior to MODEL line

5
  • 1
    Is what you want in cat /sys/class/net/wlx123456789012/device/{vendor,device}
    – meuh
    Jul 31, 2021 at 15:35
  • Thanks ! I effectivly found traces of vendor and product in the "device" folder. I edited my question. But is this solution portable between version of Debian or if I change distro ? Jul 31, 2021 at 16:45
  • @waltinator ... which would indicates a link between the vendor:product and the resultant interface ? Jul 31, 2021 at 17:01
  • 1
    There's udevadm info [-a] btw. lsusb.py -[c]ui might help as well.
    – Tom Yan
    Aug 1, 2021 at 5:41
  • @Tom Yan : Thanks ! udevadm resolved the problem. I edited my question to add udevadm way. Aug 1, 2021 at 16:49

2 Answers 2

1

I just plugged in a Ralink RT5370 wireless adapter to a Debian 10 system.

By default, it appeared as network device wlxc83a35c4a44b.

You'll need to remember that /sys/class/* is basically a directory sub-tree whose leaves are mostly symbolic links into the /sys/devices/* branch.

# realpath /sys/class/net/wlxc83a35c4a44b
/sys/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlxc83a35c4a44b
# realpath /sys/class/net/wlxc83a35c4a44b/device
/sys/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0

So the device symlink actually operates within the /sys/devices/... branch, and there is one level (1-8) in between the USB controller and the device (no USB hubs in this case). Would that level contain anything useful?

# ls --format=commas /sys/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/..
1-8:1.0/, ep_00/, power/, authorized, avoid_reset_quirk, bcdDevice,
bConfigurationValue, bDeviceClass, bDeviceProtocol, bDeviceSubClass,
bmAttributes, bMaxPacketSize0, bMaxPower, bNumConfigurations, bNumInterfaces,
busnum, configuration, descriptors, dev, devnum, devpath, driver@,
firmware_node@, idProduct, idVendor, ltm_capable, manufacturer, maxchild, port@,
product, quirks, removable, remove, rx_lanes, serial, speed, subsystem@,
tx_lanes, uevent, urbnum, version

There's idProduct and idVendor. Can we access them by just the network device name?

# cat /sys/class/net/wlxc83a35c4a44b/device/../idProduct
5370
# cat /sys/class/net/wlxc83a35c4a44b/device/../idVendor
148f

Let's verify it's the right device:

# lsusb -d 148f:5370
Bus 001 Device 014: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter

Seems correct.

And it also works without root and with a USB hub added in between:

$ realpath /sys/class/net/wlxc83a35c4a44b/device
/sys/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.2/1-7.2:1.0
$ cat /sys/class/net/wlxc83a35c4a44b/device/../idVendor
148f
$ cat /sys/class/net/wlxc83a35c4a44b/device/../idProduct
5370
3
  • Thank you ! I like this solution a lot and seems more universal, because from what I understand not all linux systems are udev based. The objective of my script is to be as "system agnostic" as possible. Also, I had never seen that giving the parent folder of a link results in the parent folder of the link target. Aug 2, 2021 at 10:33
  • In shells like bash, the cd command handles .. specially for user convenience. The bash man page says: "If .. appears in dir, it is processed by removing the immediately previous pathname component from dir, back to a slash or the beginning of dir." This is not how filesystems handle it: you can use cd -P to explicitly request using the actual .. directory entry, or use the set -P to make cd behave like this by default. So the behavior you've learned to expect is actually the exception, not the rule.
    – telcoM
    Aug 2, 2021 at 11:08
  • OK Thanks for this subtlety. Aug 2, 2021 at 13:44
1

So, based on udev @Tom Yan suggestion, to list all the Wifi USB dongle interfaces with vendor:product, I propose :

user@host:~$ for i in $( find /sys/class -name "wlx*" ) ; do \
 echo "$( echo $i | grep -oE "[^/]+$" ) $( \
  udevadm info $i \
  | awk '\
   function get_val () { split ( $0 , a , "=" ) ; return a [ 2 ] } \
   /ID_VENDOR_ID/ { v = get_val() } \
   /ID_MODEL_ID/ { m = get_val() } \
   END { print v ":" m }\
  ' \
 )" ; \
done
wlx123456789012 2357:0109

Explanations : for each interface ( for i in ... ; do ... ; done ), list all wifi USB dongle interfaces pathes ( find /sys/class -name "wlx*" ) and for each path get and display only interface name ( echo $i | grep -oE "[^/]+$" ) so /sys/class/net/wlx123456789012 -> wlx123456789012, get all udev properties and filter these properties( udevadm info $i | awk ... ).

The filtering process :

  • create a function which divides the current record ($0) with the equal char ("=") and stores the result in the "a" array and returns the 2nd member of "a" so ID value ( function get_val )

  • filter and store the value ( /ID_VENDOR_ID/ ... and /ID_MODEL_ID/ ... )

  • finally print the stored values in the correct order vendor:model ( END { ... } )


And based on @telcoM more system agnostic and simple way :

user@host:~$ for i in $( find /sys/class/net/ -type l -name "wlx*" ) ; do \
 echo "$( \
  echo $i | grep -oE "[^/]+$" \
 ) $( \
  cat $i/device/../idVendor \
 ):$( \
  cat $i/device/../idProduct \
 )" ; \
done
wlx123456789012 2357:0109

Explanations : for each interface ( for i in ... ; do ... ; done ), list all wifi USB dongle interfaces links ( find /sys/class/net -type l -name "wlx*" ) and for each link get and display only interface name ( echo $i | grep -oE "[^/]+$" ) so /sys/class/net/wlx123456789012 -> wlx123456789012, and display the idVendor content from the link parent folder and do the same with idProduct

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .