morrownr / USB-WiFi

USB WiFi Adapter Information for Linux
2.4k stars 161 forks source link

Switching between channels with MT7612U (AWUS036ACM) very slow #376

Open FeldrinH opened 4 months ago

FeldrinH commented 4 months ago

I have a AWUS036ACM USB WiFi adapter. I am using it in monitor mode to capture packets while hopping through channels. For this I have Wireshark capturing packets and a script running that uses sudo iw <interface> set channel <channel> to switch between channels periodically. I noticed that every run of iw takes about 450 ms, during which Wireshark appears to capture nothing.

For a modern computer, 450 ms seems like a very long time. Running iw with the time command gives very low sys and user times, indicating that most of the time is spent idle waiting for something.

Is 450 ms to switch between channels normal/expected? Is there something that could be done to shorten this time? Is this an issue with MT7612U specifically or are other WiFi chips just as slow to switch between channels?

Some tangentially related resources online seem to indicate that channel hopping should be possible at much faster rates (for example Kismet's default channel hopping frequency is 5 Hz, which is only 200 ms per channel, less than half the time it takes my AWUS036ACM to complete a single channel switch).

Any insight would be much appreciated. I don't really have a good frame of reference, since I haven't looked at the channel hopping speed of WiFi adapters before. I also haven't found a single relevant resource online about how long switching between channels is supposed to take with a USB WiFi adapter.

PS: The system used is Ubuntu 22.04 running on an Intel NUC, in case that is relevant. I also got similar times on Debian running in VirtualBox on a Windows 10 host.

morrownr commented 4 months ago

Hi @FeldrinH

Interesting. I have 25+ adapters here and I am will to run some tests so we can get enough results to see what is normal.

Do you know how to write scripts or BASH?

The reason that I ask is because having the lines in a script could greatly reduce the amount of time this would take.

I actually have a script that has to do with monitor mode. You could take it and change it to help in this case:

start-mon.sh

https://github.com/morrownr/Monitor_Mode

I have tried to comment the code so that it is easier to understand.

@morrownr

FeldrinH commented 4 months ago

Interesting. I have 25+ adapters here and I am will to run some tests so we can get enough results to see what is normal.

That would be very helpful.

I don't really know bash that well. I've got a Python script I used for testing:

import statistics
import subprocess
import sys
import time

# Before use: run `airmon-ng check kill` or otherwise disable services that might interfere with monitor mode

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Wrong number of arguments")
        print(f"Usage: python {sys.argv[0]} interface")
        sys.exit(1)

    iface = sys.argv[1]

    # Enable monitor mode
    subprocess.run(['sudo', 'ip', 'link', 'set', iface, 'down']).check_returncode()
    subprocess.run(['sudo', 'iw', iface, 'set', 'type', 'monitor']).check_returncode()
    subprocess.run(['sudo', 'ip', 'link', 'set', iface, 'up']).check_returncode()

    # Start at channel 6 initially
    subprocess.run(['sudo', 'iw', iface, 'set', 'channel', '6']).check_returncode()

    channels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

    times = []
    for channel in channels:
        # Switch to channel and measure time taken
        start = time.perf_counter()
        subprocess.run(['sudo', 'iw', iface, 'set', 'channel', str(channel)]).check_returncode()
        end = time.perf_counter()

        # Log time
        time_ms = (end - start) * 1000
        times.append(time_ms)
        print(f"Switching to channel {channel}: {time_ms:.2f} ms")

        # Grace period (sleep for 200 ms)
        time.sleep(0.2)

    print(f"Average: {statistics.mean(times):.2f} ms")
FeldrinH commented 4 months ago

My own results with MT7612U:

Switching to channel 1: 444.84 ms
Switching to channel 2: 460.44 ms
Switching to channel 3: 460.07 ms
Switching to channel 4: 450.63 ms
Switching to channel 5: 446.36 ms
Switching to channel 6: 449.70 ms
Switching to channel 7: 449.91 ms
Switching to channel 8: 448.35 ms
Switching to channel 9: 449.77 ms
Switching to channel 10: 450.36 ms
Switching to channel 11: 455.30 ms
Average: 451.43 ms
morrownr commented 4 months ago

What does the script name need to be and should I use the interface name as a parameter? I'll give it a run.

I've never used python. I do understand what most of the code is doing. I can probably add this to my scripts is a few minutes. That would save time running airmon as my script pauses the interfering processes. I find that to be much more effective than trying to kill processes that do not want to be killed.

FeldrinH commented 4 months ago

What does the script name need to be and should I use the interface name as a parameter? I'll give it a run.

Yes, it takes one parameter which is the interface name to pass to iw and ip. Script name doesn't really matter.

FeldrinH commented 4 months ago

Oh, just in case: I tested this with Python 3.10, but it should work with Python 3.6 and newer.

morrownr commented 4 months ago

mt7922 PCIe card:

$ python3 scan.py wlp3s0 Switching to channel 1: 166.90 ms Switching to channel 2: 163.98 ms Switching to channel 3: 160.52 ms Switching to channel 4: 165.34 ms Switching to channel 5: 160.55 ms Switching to channel 6: 169.14 ms Switching to channel 7: 160.94 ms Switching to channel 8: 170.69 ms Switching to channel 9: 161.36 ms Switching to channel 10: 168.55 ms Switching to channel 11: 164.46 ms Average: 164.77 ms

Alfa ACM mt7612u:

$ python3 scan.py wlx00c0caadcb84 Switching to channel 1: 432.31 ms Switching to channel 2: 427.91 ms Switching to channel 3: 431.97 ms Switching to channel 4: 431.03 ms Switching to channel 5: 433.91 ms Switching to channel 6: 430.23 ms Switching to channel 7: 431.65 ms Switching to channel 8: 430.01 ms Switching to channel 9: 428.89 ms Switching to channel 10: 432.59 ms Switching to channel 11: 432.56 ms Average: 431.19 ms

I can try more later, I have somewhere to be for now.

morrownr commented 4 months ago

More:

Alfa AXML mt7921au:

$ python3 scan.py wlxe0e1a935c51f
Switching to channel 1: 29.63 ms
Switching to channel 2: 132.80 ms
Switching to channel 3: 133.51 ms
Switching to channel 4: 132.08 ms
Switching to channel 5: 133.11 ms
Switching to channel 6: 132.07 ms
Switching to channel 7: 131.68 ms
Switching to channel 8: 136.12 ms
Switching to channel 9: 133.61 ms
Switching to channel 10: 133.25 ms
Switching to channel 11: 133.87 ms
Average: 123.80 ms

Alfa ACHM mt7610u:

$ python3 scan.py wlx00c0caad4bcc
Switching to channel 1: 57.58 ms
Switching to channel 2: 56.39 ms
Switching to channel 3: 59.85 ms
Switching to channel 4: 59.46 ms
Switching to channel 5: 59.64 ms
Switching to channel 6: 60.77 ms
Switching to channel 7: 60.87 ms
Switching to channel 8: 58.23 ms
Switching to channel 9: 62.98 ms
Switching to channel 10: 64.46 ms
Switching to channel 11: 65.01 ms
Average: 60.48 ms

Okay, there you have two more tests. The mt7921au and mt7610u chipsets are both considerably faster than the mt7612u chipset in this test.

For further tests, would you like tests with single band adapters or with the rtl8812bu using the in-kernel driver?

FeldrinH commented 4 months ago

For further tests, would you like tests with single band adapters or with the rtl8812bu using the in-kernel driver?

I don't really have a strong preference. Testing a Realtek adapter for comparison would definitely be useful.

morrownr commented 4 months ago

More:

Alfa ACU rtl8812bu: (in-kernel driver, kernel 6.5)

$ python3 scan.py wlx00c0caadde9e
[sudo] password for morrow:         
Switching to channel 1: 14.53 ms
Switching to channel 2: 13.44 ms
Switching to channel 3: 14.68 ms
Switching to channel 4: 14.02 ms
Switching to channel 5: 14.93 ms
Switching to channel 6: 15.36 ms
Switching to channel 7: 17.13 ms
Switching to channel 8: 15.41 ms
Switching to channel 9: 15.08 ms
Switching to channel 10: 13.63 ms
Switching to channel 11: 16.56 ms
Average: 14.98 ms

This rtl8812bu based adapter is fast in this test but let me throw some things out:

Generic rt5370 single band:

$ python3 scan.py wlx08ea35e122e3
Switching to channel 1: 16.74 ms
Switching to channel 2: 20.92 ms
Switching to channel 3: 20.48 ms
Switching to channel 4: 19.86 ms
Switching to channel 5: 20.09 ms
Switching to channel 6: 18.87 ms
Switching to channel 7: 20.25 ms
Switching to channel 8: 20.16 ms
Switching to channel 9: 19.16 ms
Switching to channel 10: 20.55 ms
Switching to channel 11: 20.56 ms
Average: 19.79 ms

Let me know what else I can test for you.

@morrownr

bjlockie commented 4 months ago

mt7921au

That seems slow compared to the mt7610u. :-(

morrownr commented 4 months ago

@bjlockie

That seems slow compared to the mt7610u. :-(

It does. It would interesting to test 5 GHz.

The mt7921au is tri-band and to have optimal antennas for each band, you would need 5 antennas. I wonder if part of what we are seeing is because of something similar to that.

FeldrinH commented 4 months ago

It does. It would interesting to test 5 GHz.

You can easilly change the list of channels in the original script. This should be a pretty representative sample of 5 GHz channels:

    channels = [36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 149, 153, 157, 161, 165, 169, 173]

I don't currently have my MT7612U on hand, but I previously tested it with channels 149-173 and got an average time of ~580 ms.

FeldrinH commented 4 months ago

Let me know what else I can test for you.

I don't currently have any ideas for specific adapters to test. What I would really appreaciate is some kind of explanation for the existing results, if anyone has any insight. Why is the MT7612U so much slower? What is the adapter/driver doing for those 400+ ms that my computer sits idle waiting for the channel to change? Why are the Realtek adapters so much faster at changing channels?

morrownr commented 4 months ago

Why is the MT7612U so much slower?

Go ahead and take a look:

https://github.com/torvalds/linux/tree/master/drivers/net/wireless/mediatek/mt76

I have no idea but I'm sure we can get close to an answer by working through the code.

dubhater commented 4 months ago

You could ask on the mailing list. The developers are active there. Maybe they already know exactly why this chip is slower to switch the channels. The address is linux-wireless@vger.kernel.org. It accepts only plain text emails.