Ten Wifi Dongles At Once
I used to try to do one dumb/weird hardware thing every year. One year, I used a Palm Pilot as a serial terminal for a Sun SPARCStation-10. Multiple serial cable adapters and gender changers involved.
My dumb hardware stunt for October 2024: 10 USB WiFi adapters on the same laptop.
Top row, left to right: Airlink, TP-Link TL-WN725N, TP-Link Archer T3U TP-Link TL-WN722N, TP-Link TL-WN821N
Second row down: TP-Link AC 1200
Third row down: TP-Link Archer T2U Plus
Bottom row, left to right: D-Link DWA-171A, Netgear A6210, Wi-Pi™
Model | Chip set | USB ID | MAC Address | Kernel module |
---|---|---|---|---|
Airlink | Realtek RTL8188CUS | 0bda:8176 | 00:21:2f:3a:75:50 | rtl8xxxu |
D-Link DWA-171A1 | Realtek RTL8811AU | 2001:3314 | c4:12:f5:de:67:36 | 8821au |
Netgear A6210 | Mediatek MT7612U | 0846:9053 | 6c:cd:d6:c0:dc:7d | mt76x2u |
TP-Link AC 1200 | RTL88x2bu | 0bda:b812 | 00:13:ef:f2:4d:bd | rtw88_8822bu |
TP-Link Archer T2U Plus | RTL8821AU | 2357:0120 | 98:48:27:3f:c0:95 | 8821au |
TP-Link T3U | RTL8812BU | 1d6b:0003 | d0:37:45:50:60:0a | rtw88_8822bu |
TP-Link TL-WN722N | Atheros AR9271 802.11n | 0cf3:9271 | e8:de:27:a1:77:ea | ath9k_htc |
TP-Link TL-WN725N | RTL8188EUS | 0bda:8179 | b4:b0:24:e0:89:88 | rt2800usb |
TP-Link TL-WN821N | Atheros AR7010+AR9287 | 0cf3:7015 | f8:d1:11:14:79:21 | ath9k_htc |
Wi-Pi™ | Ralink RT5370 | 148f:5370 | 40:a5:ef:07:1c:8d | rt2800usb |
Device Drivers
We’re constantly told that Linux device drivers, in particular WiFi drivers, are in a depressingly poor state. I did not find that to be the case.
Six of the adapters Just Worked™, but I had to fiddle a bit for the other four. I’m doing this on a Dell E7470 Latitude laptop running Arch Linux, with kernel 6.11.1-zen1-1-zen.
Wi-Pi and TP-Link TL-WN725N: sudo modprobe -v rt2800usb
The kernel driver was included in Linux 6.11.1, but it didn’t get loaded automatically.
I’m a little mystified by how automatic module loading works in general
DWA-171A and T2U Plus: had to compile a kernel driver from source.
Here’s what lsusb
says about these two WiFi adapters:
Bus 001 Device 021: ID 2001:3314 D-Link Corp. DWA-171 AC600 DB Wireless Adapter(rev.A1) [Realtek RTL8811AU]
Bus 001 Device 024: ID 2357:0120 TP-Link Archer T2U PLUS [RTL8821AU]
I tried three from-source drivers, rtl88xxau-aircrack-dkms-git from the Arch AUR, and two Github repositories, morrownr/8821cu-20210916 and brektrou/rtl8821CU. The AUR driver caused kernel “oops” that prevented me from killing processes, the other two couldn’t find either adapter.
I ended up using morrownr/8821au-20210708. It strangely works for both DWA-171 and T2U PLUS, despite the DWA-171 identifying as having the RTL8811AU chip set.
Each adapter, used individually, could associate with my WiFi access points,
and dhcpcd
could acquire an IPv4 address, and a route.
13 Socket externally-powered USB Hub
You can’t plug in more USB devices than your computer has physical USB sockets. I purchased an externally powered USB hub a few years ago by mistake. I was trying to make a Raspberry Pi Kubernetes cluster, and I needed to power a bunch of Raspberry Pi boards. This was not the solution to that problem.
It has no brand name or other markings on it.
After you plug it in, lsusb
has this to say about it:
Bus 001 Device 017: ID 14cd:8601 Super Top 4-Port hub
Bus 001 Device 018: ID 14cd:8601 Super Top 4-Port hub
Bus 001 Device 019: ID 14cd:8601 Super Top 4-Port hub
Bus 001 Device 020: ID 14cd:8601 Super Top 4-Port hub
The adapters closest to the power socket got hot over the 30 minutes
or so it took me to plug everything in,
copy a wpa_supplicant
config file, and turn the device up.
This seems like a flaw.
It Worked!
There’s only 9 adapters visible in the view above. The DWA-171 is obscured by the tall antenna of the T2U PLUS or the AC1200. It’s in slot 8 of the USB hub.
I plugged in each USB WiFi adapter one a time,
creating a wpa_supplicant
configuration file
then using ip link set dev $SOMETHING up
to activate.
The steps go something like this:
- Plug in adapter
- Watch
journalctl -f
output to see the kernel recognize a new USB device - Run
ip -br link
to find the weird interface name assigned cp /etc/wpa_supplicant/wpa-supplicant-wlp1s0.conf /etc/wpa_supplicant/wpa-supplicant-$NEWDEVICE.conf
systemctcl start wpa-supplicant@$NEWDEVICE
ip link set dev $NEWDEVICE up
- Watch
journalctl -f
output to seedhcpcd
acquire a new IPv4 address
Addresses and weird interface names`
Here’s how the IPv4 addresses initially got assigned.
1142 % ip -br address
lo UNKNOWN 127.0.0.1/8 ::1/128
enp0s31f6 DOWN
wlp1s0 UP 10.0.20.35/24 fe80::3dde:54b1:a20f:b816/64
wlp0s20f0u1u1u4 UP 10.0.20.105/24 fe80::cc9:a944:a2b9:ad10/64
wlp0s20f0u1u1u3 UP 10.0.20.106/24 fe80::26f7:9acb:59eb:9fa4/64
wlp0s20f0u1u2u4 UP 10.0.20.107/24 fe80::f38b:6cc3:4cc9:c176/64
wlp0s20f0u1u1u2 UP 10.0.20.108/24 fe80::a4df:5208:9156:27cb/64
wlp0s20f0u1u2u1 UP 10.0.0.109/24 fe80::46b:a293:5e35:13a2/64
wlp0s20f0u1u2u3 UP 10.0.20.109/24 fe80::603e:92db:fd1:37ca/64
wlp0s20f0u1u3u3 UP 10.0.0.110/24 fe80::acb4:a169:9184:9ef/64
wlp0s20f0u1u3u2 UP 10.0.0.111/24 fe80::bd64:56b9:c6c7:eb6d/64
wlp0s20f0u1u3u1 UP 10.0.0.112/24 fe80::ba50:d06d:2a37:e935/64
wlp0s20f0u1u4 UP 10.0.20.110/24 fe80::ee1e:4996:8dea:1c60/64
I have three Linksys Velop wireless access points placed strategically around my house. Each one has a CAT-5 cable running back to my Dell R530 server. They’re in “bridge mode” so that my server can control IP addresses and routing, consolidate NTP and DNS. My desk is roughly equidistant from the access point that has address 10.0.0.1 and the access point that has address 10.0.20.1. kea-dhcp4 gives out 10.0.0.0/24 or 10.0.20.0/24 addresses from pools appropriately.
enp0s31f6
is the name of the CAT-5 ethernet cable port.
wlp1s0
is my laptop’s built-in WiFi device.
Interface name | MAC Address | WiFi adapter |
---|---|---|
wlp0s20f0u1u1u2 | d0:37:45:50:60:0a | TP-Link T3U |
wlp0s20f0u1u3u1 | 98:48:27:3f:c0:95 | TP-Link Archer T2U Plus |
wlp0s20f0u1u4 | 40:a5:ef:07:1c:8d | Wi-Pi™ |
wlp0s20f0u1u2u1 | e8:de:27:a1:77:ea | TP-Link TL-WN722N |
wlp0s20f0u1u3u2 | c4:12:f5:de:67:3c | D-Link DWA-171A1 |
wlp0s20f0u1u1u3 | b4:b0:24:e0:89:88 | TP-Link TL-WN725N |
wlp0s20f0u1u2u3 | 6c:cd:d6:c0:dc:7d | Netgear A6210 |
wlp0s20f0u1u3u3 | 00:13:ef:f2:4d:bd | TP-Link AC 1200 |
wlp0s20f0u1u1u4 | f8:d1:11:14:79:21 | TP-Link TL-WN821N |
wlp0s20f0u1u2u4 | 00:21:2f:3a:75:50 | Airlink |
I’m in the dark about how interface names are assigned. I suspect that the names have something to do with how many USB hubs are chained, but I’m not certain.
Routing Table
Just to see how weird this got, here’s ip -br route
output:
default via 10.0.20.1 dev wlp1s0 proto dhcp src 10.0.20.35 metric 3004
default via 10.0.20.1 dev wlp0s20f0u1u1u4 proto dhcp src 10.0.20.105 metric 3018
default via 10.0.20.1 dev wlp0s20f0u1u1u3 proto dhcp src 10.0.20.106 metric 3019
default via 10.0.20.1 dev wlp0s20f0u1u2u4 proto dhcp src 10.0.20.107 metric 3020
default via 10.0.20.1 dev wlp0s20f0u1u1u2 proto dhcp src 10.0.20.108 metric 3021
default via 10.0.0.1 dev wlp0s20f0u1u2u1 proto dhcp src 10.0.0.109 metric 3022
default via 10.0.20.1 dev wlp0s20f0u1u2u3 proto dhcp src 10.0.20.109 metric 3023
default via 10.0.0.1 dev wlp0s20f0u1u3u3 proto dhcp src 10.0.0.110 metric 3024
default via 10.0.0.1 dev wlp0s20f0u1u3u2 proto dhcp src 10.0.0.111 metric 3025
default via 10.0.0.1 dev wlp0s20f0u1u3u1 proto dhcp src 10.0.0.112 metric 3026
default via 10.0.20.1 dev wlp0s20f0u1u4 proto dhcp src 10.0.20.110 metric 3027
10.0.0.0/24 dev wlp0s20f0u1u2u1 proto dhcp scope link src 10.0.0.109 metric 3022
10.0.0.0/24 dev wlp0s20f0u1u3u3 proto dhcp scope link src 10.0.0.110 metric 3024
10.0.0.0/24 dev wlp0s20f0u1u3u2 proto dhcp scope link src 10.0.0.111 metric 3025
10.0.0.0/24 dev wlp0s20f0u1u3u1 proto dhcp scope link src 10.0.0.112 metric 3026
10.0.20.0/24 dev wlp1s0 proto dhcp scope link src 10.0.20.35 metric 3004
10.0.20.0/24 dev wlp0s20f0u1u1u4 proto dhcp scope link src 10.0.20.105 metric 3018
10.0.20.0/24 dev wlp0s20f0u1u1u3 proto dhcp scope link src 10.0.20.106 metric 3019
10.0.20.0/24 dev wlp0s20f0u1u2u4 proto dhcp scope link src 10.0.20.107 metric 3020
10.0.20.0/24 dev wlp0s20f0u1u1u2 proto dhcp scope link src 10.0.20.108 metric 3021
10.0.20.0/24 dev wlp0s20f0u1u2u3 proto dhcp scope link src 10.0.20.109 metric 3023
10.0.20.0/24 dev wlp0s20f0u1u4 proto dhcp scope link src 10.0.20.110 metric 3027
ssh to every interface
I used ssh
to log in from one interface to another.
I’m not convinced the TCP packets went out one interface,
and back into another, however.
They might all have been routed internally.
1001 % who
bediger tty1 Oct 5 22:19
bediger pts/0 Oct 5 22:19 (:0)
bediger pts/1 Oct 5 22:19 (:0)
bediger pts/2 Oct 5 22:19 (:0)
bediger pts/3 Oct 5 22:19 (:0)
bediger pts/4 Oct 8 14:11 (:0)
bediger pts/5 Oct 6 20:44 (:0)
bediger pts/6 Oct 8 15:03 (10.0.20.35)
bediger pts/7 Oct 8 15:03 (10.0.20.105)
bediger pts/8 Oct 8 15:03 (10.0.20.106)
bediger pts/9 Oct 8 15:03 (10.0.20.107)
bediger pts/10 Oct 8 15:04 (10.0.20.108)
bediger pts/11 Oct 8 15:04 (10.0.20.109)
bediger pts/12 Oct 8 15:05 (10.0.0.110)
bediger pts/13 Oct 8 15:05 (10.0.0.111)
bediger pts/14 Oct 8 15:05 (10.0.0.112)
bediger pts/15 Oct 8 15:05 (10.0.20.110)
I probably should have ssh'ed
to each interface from my R530,
just to insure that all interfaces work simultaneously.
The view from my router
I logged in to my router, a Dell R530 rack mount with far too many
ethernet ports that is set to use monarch
as it’s host name.
Here’s what I could see.
bediger@monarch
1013 % ip n
10.0.0.43 dev eno1 lladdr 00:e0:4c:68:22:34 REACHABLE
10.0.20.77 dev eno4 lladdr c4:41:1e:4e:38:03 REACHABLE
10.0.0.42 dev eno1 FAILED
10.0.10.105 dev eno2 FAILED
10.0.10.104 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.30.77 dev ens4 FAILED
10.0.20.124 dev eno4 lladdr 8c:49:62:46:f4:f4 REACHABLE
10.0.10.106 dev eno2 FAILED
10.0.10.109 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.108 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.0.35 dev eno1 FAILED
10.0.20.123 dev eno4 lladdr f8:ff:c2:0e:54:57 STALE
10.0.0.105 dev eno1 lladdr f8:ff:c2:0e:54:57 STALE
10.0.0.104 dev eno1 FAILED
10.0.0.107 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.0.106 dev eno1 FAILED
10.0.0.109 dev eno1 lladdr e8:de:27:a1:77:ea REACHABLE
10.0.10.101 dev eno2 FAILED
10.0.0.108 dev eno1 lladdr 40:a5:ef:07:1c:8d STALE
10.0.10.100 dev eno2 FAILED
10.0.10.103 dev eno2 FAILED
10.0.10.102 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.20.100 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.20.102 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.40.70 dev ens5 lladdr 20:7c:14:f3:83:05 STALE
10.0.0.101 dev eno1 lladdr 50:14:79:9d:fd:3e STALE
10.0.0.100 dev eno1 lladdr c4:41:1e:4e:38:3f STALE
10.0.0.103 dev eno1 FAILED
10.0.0.102 dev eno1 FAILED
10.0.10.77 dev eno2 lladdr c4:41:1e:4e:37:b5 REACHABLE
10.0.20.101 dev eno4 lladdr 98:48:27:3f:c0:95 STALE
10.0.20.100 dev eno4 lladdr 74:74:46:cb:d9:d9 STALE
10.0.20.103 dev eno4 FAILED
10.0.20.102 dev eno4 FAILED
10.0.0.104 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.0.106 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.0.42 dev eno4 lladdr a8:8f:d9:30:4d:54 STALE
10.0.10.101 dev eno4 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.106 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.109 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.108 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.102 dev eno4 lladdr 74:74:46:cb:d9:d9 STALE
10.0.20.42 dev eno4 lladdr a8:8f:d9:30:4d:54 STALE
10.0.0.69 dev eno1 lladdr 00:17:c8:c0:de:d1 STALE
10.0.0.103 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.101 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.0.102 dev eno2 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.100 dev eno1 lladdr 50:14:79:9d:fd:3e STALE
10.0.20.35 dev eno4 lladdr e4:a4:71:30:21:86 REACHABLE
10.0.10.103 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.102 dev eno1 lladdr 74:74:46:cb:d9:d9 STALE
10.0.10.35 dev eno2 FAILED
fe80::3dde:54b1:a20f:b816 dev eno4 lladdr e4:a4:71:30:21:86 STALE
fe80::c641:1eff:fe4e:3803 dev eno4 lladdr c4:41:1e:4e:38:03 router STALE
fe80::acb4:a169:9184:9ef dev eno1 lladdr 00:13:ef:f2:4d:bd STALE
fe80::c641:1eff:fe4e:383f dev eno1 lladdr c4:41:1e:4e:38:3f router STALE
fe80::c641:1eff:fe4e:37b5 dev eno2 lladdr c4:41:1e:4e:37:b5 router STALE
IPv6 pings
IPv6 is weird. It has all these broadcast addresses, like ff02::1, the link-local broadcast address for all nodes. I tried this address on my Dell R530. I had to specify which interface on the R530 to send out the ping, because IPv6 routing is so dang complicated.
“eno1” is the R530’s 10.0.0.1 interface, and “eno4” is the 10.0.20.1 interface. Each WiFi access point is plugged in to a different ethernet socket on the R530.
PING ff02::1%eno1 (ff02::1%eno1) 56 data bytes
64 bytes from fe80::46a8:42ff:fe2d:c255%eno1: icmp_seq=1 ttl=64 time=0.022 ms
64 bytes from fe80::217:c8ff:fec0:ded1%eno1: icmp_seq=1 ttl=255 time=0.426 ms
64 bytes from fe80::c641:1eff:fe4e:383f%eno1: icmp_seq=1 ttl=64 time=0.441 ms
64 bytes from fe80::f38b:6cc3:4cc9:c176%eno1: icmp_seq=1 ttl=64 time=59.0 ms
64 bytes from fe80::cc9:a944:a2b9:ad10%eno1: icmp_seq=1 ttl=64 time=59.8 ms
64 bytes from fe80::acb4:a169:9184:9ef%eno1: icmp_seq=1 ttl=64 time=74.3 ms
64 bytes from fe80::a4df:5208:9156:27cb%eno1: icmp_seq=1 ttl=64 time=74.5 ms
64 bytes from fe80::ba50:d06d:2a37:e935%eno1: icmp_seq=1 ttl=64 time=75.3 ms
64 bytes from fe80::603e:92db:fd1:37ca%eno1: icmp_seq=1 ttl=64 time=79.7 ms
64 bytes from fe80::549b:6750:dafc:1684%eno1: icmp_seq=1 ttl=64 time=140 ms
If you look closely, you can see the IPv6 addresses of TP-Link T3U, TP-Link Archer T2U Plus, Netgear A6210, TP-Link AC 1200, TP-Link TL-WN821N, Airlink.
On the other interface, which should be 10.0.20.0/24 addresses:
PING ff02::1%eno4 (ff02::1%eno4) 56 data bytes
64 bytes from fe80::46a8:42ff:fe2d:c258%eno4: icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from fe80::c641:1eff:fe4e:3803%eno4: icmp_seq=1 ttl=64 time=0.712 ms
64 bytes from fe80::8e49:62ff:fe46:f4f4%eno4: icmp_seq=1 ttl=64 time=11.4 ms
64 bytes from fe80::3dde:54b1:a20f:b816%eno4: icmp_seq=1 ttl=64 time=77.3 ms
64 bytes from fe80::bd64:56b9:c6c7:eb6d%eno4: icmp_seq=1 ttl=64 time=83.7 ms
64 bytes from fe80::46b:a293:5e35:13a2%eno4: icmp_seq=1 ttl=64 time=106 ms
I only find the IPv6 address of D-Link DWA-171A1.
I think I futzed around too long between pings.
dhcpcd
must have switched some interface from 10.0.20.0/24 addresses
to 10.0.0.0/24 addresses, so I missed them in the second ping.
Addresses flip as time progresses
Remember that I wrote that my laptop and all 10 dongles were about equidistant from each of 2 access points? Over time, DHCP renewals switched access points:
ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
enp0s31f6 DOWN
wlp1s0 UP 10.0.20.35/24 fe80::3dde:54b1:a20f:b816/64
wlp0s20f0u1u1u2 UP 10.0.0.113/24 fe80::a4df:5208:9156:27cb/64
wlp0s20f0u1u3u1 UP 10.0.0.112/24 fe80::ba50:d06d:2a37:e935/64
wlp0s20f0u1u4 UP 10.0.20.110/24 fe80::ee1e:4996:8dea:1c60/64
wlp0s20f0u1u2u1 UP 10.0.20.104/24 fe80::46b:a293:5e35:13a2/64
wlp0s20f0u1u3u2 UP 10.0.20.111/24 fe80::bd64:56b9:c6c7:eb6d/64
wlp0s20f0u1u1u3 UP 10.0.0.115/24 fe80::26f7:9acb:59eb:9fa4/64
wlp0s20f0u1u2u3 UP 10.0.0.116/24 fe80::603e:92db:fd1:37ca/64
wlp0s20f0u1u3u3 UP 10.0.0.110/24 fe80::acb4:a169:9184:9ef/64
wlp0s20f0u1u1u4 UP 10.0.0.117/24 fe80::cc9:a944:a2b9:ad10/64
wlp0s20f0u1u2u4 UP 10.0.0.114/24 fe80::f38b:6cc3:4cc9:c176/64
My kea-dhcp4
must give out very short lease times, or something.
dhcpcd
is weird about how long to retain a lease as opposed to how long the
server says the lease is good for.
The other factor is the WiFi access points are in bridging mode. I don’t believe they can cooperate to hand off a connection.