Mini Howto of WiFi (power) tuning (not only) under Linux

Dr. Rolf Freitag <rolf dot freitag at email dot de>

Version 1.20 from 2014-01-20

0 Foreword

For every tuning you have to bear in mind the regulatory compliance of the country where you are doing the tuning, when you are not in an absorber chamber/Anechoic RF chamber or similar place like a room beneath the ground.
Using unnecessary high RF output power is inefficient, a waste of energy, money and it disturbs other people which are using WiFi.
Another aspect is that when you use unnecessary high power unnecessary many people and organisations more can receive your transmission.
So tuning of the output power should only be done when you need it or for short tests.
For the health the tuning is irrelevant because other RF sources have more power than WiFi adapters, e. g. cellular phones about 2 W total, medical RF emitters several W more and the sun about 1 kW per square meter. And a microwave oven can legally emitt up to 0.1 %, which is 1 W from a 1000 W microwave oven, right between WiFi channel 9 and 10, at 2.455 GHz.

1 Choosing the best region/country

The WiFi regulations are country specific, implemented as Central Regulatory Domain Agent, short CRDA.
CRDA relies on nl80211 for communication and acts as the udev helper for communication between the kernel and userspace for regulatory compliance.
The current settings can be displayes with "iw reg get".
> iw reg get
country BO:
        (2402 - 2482 @ 40), (N/A, 30)
        (5735 - 5835 @ 40), (N/A, 30)
The output shows the WiFi ranges availible, with up to 40 MHz bandwidth and up to 30 dBm = 1 Watt power.
The country 00 is worldwide, with minimum values which are allowed in every country. This country is the default and used when the database, regulatory.bin, can not be found or is not valid signed.
The command
regdbdump /lib/crda/regulatory.bin
regdbdump /usr/lib/crda/regulatory.bin
shows the list of availible countries.
This reduces the numer of availible WiFi channels and the output power, which can be set via "iwconfig <device> <txpower in dBm>" and also the power which can be set via "iwpriv <device> highpower" and other commands.
So in theory countries with a high power limit like BO (Bolivia) should be optimal, but at my Zioncom WL0161 adapter i could not verify this. I used Ubuntu 13.04 64 Bit, Kernel 3.8.0-31-generic, switching from BO to 00 by renaming the regulatory.bin, unloading and loading the module cfg80211 to make the change effective and measured with the RF detector CPDETLS-4000 with a 20 dB attenuator and this program for calculating the power from the detector voltage measured with a DMM. The result was that the output power was changed from 19.3 dBm to 22.6 dBm, which means 100 % more power (in Milliwatt).
So to get the maximum power the best country in reality must be found out by measuring the output/RF power under several countries, by selecting the country via "iw reg set <countrycode>". This also affects other parameters like the list of availible channels.

I also tried tuning the default values, e. g. with
                /* nearly everything, with max. 40 MHz bandwidth, max. 99 dBm, only for testing */
                REG_RULE(1000-20, 9995+20, 40, 6, 99, 0),
                REG_RULE(10000-20, 19995+20, 40, 6, 99, 0),
                REG_RULE(20000-20, 49995+20, 40, 6, 99, 0),
                REG_RULE(50000-1080, 69995+1080, 2160, 6, 99, 0),
                REG_RULE(70000-1080, 89995+1080, 2160, 6, 99, 0),
                REG_RULE(90000-1080, 99995+1080, 2160, 6, 99, 0),
in the kernel sources in net/wireless/reg.c, and after compiling and loading the module cfg80211 but that did not gave more power from the WL0162.
I got the same result, not more power, by only increasing the default values to 99 (dBm).

2 Tuning the MTU

Tuning the MTU does not change the power but is usefull for weak connections and for connections with many distortions and therefore a high packet loss rate. Lowering the MTU reduces the packet size and this reduces the probability that a packet gets so damaged that it can not be received correctly. But the price of a lower MTU is more overhead, so the MTU should not be too small and not be too big.
The packet loss can be checked with ping -M do -s <packetsize>, with "-M do" for unfragmented packets.
So a simple one-liner to find the maximum MTU is
ifconfig wlan0 mtu 2304; for i in `seq 68 3000`; do ping -W 1 -c 1 -M do -s $i >/dev/null 2>&1; echo $i $?; done | less
The last number is the return code and 0 if successfull, 1 if ping does not receive any reply packets at all and 2 on other error.
The maximum MTU is the highest size with return code 0, but the ping size is the net size = MTU -28, e. g. 1472 for a MTU of 1500. At weak connections this value varies and is not a clear limit because loosing packets is a statistical process, espacially at WiFi. Therefore deterministic tools like tracepath can usually only detect the commanded MTU, not the MTU to which a packet gets transmitted with a probability of (nearly) 100 %. You can see this by setting the MTU of the adapter to 2304 and tracepath -n to an AP with a lower MTU.
Setting half the value of the measured average maximum MTU is usually a good choice and should give a packet loss rate much lower than 10 %.

The current minimal maximum MTU is the maximum MTU with no packet loss and can be estimated by finding the biggest unfragmented ping size:
# Simple current minimal maximum MTU estimation, with the IP as script argument.

# no unset variables
set -u

MinPingSize=57 # net size (without 28 bytes of overhead)
PKT_SIZE=$MinPingSize # ping start size
PingHost=$1 # other side, e. g. AP

# ping with 56 bytes default size
ping -W 1 -c 1 $PingHost >/dev/null 2>&1
if [ $retval -ne 0 ] ; then
  echo "Can't ping $PingHost at all."
  echo "$PingHost seems to be alive; proceeding."
# ping till ping fails
while [ $retval -eq 0 ] ; do
  ping -W 1 -M do -c 1 -s $PKT_SIZE $PingHost >/dev/null 2>&1
  if [ $PKT_SIZE -ge 3000 ] ; then
  if [ $retval -eq 0 ] ; then # increase ping size only if successfull
  echo -n .

# Now we are at the first failed ping; decrease to the last successfull ping size.
if [ $retval -ne 0 ] ; then
printf "The current minimal maximum MTU is $((PKT_SIZE + 28)) \n"
exit 0
You can see the statistical variations of the current minimal maximum MTU after setting the MTU of the adapter to 2304, the common kernel limit for Wifi adapters, and the script via
while true; do ./ | grep MTU; done
This also showed that with a Centrino Advanced-N 6235 or AWUS036NEH setting a MTU lower then 552, e. g. 256, works without an error and ifconfig shows this new MTU but the testing with pings, under Ubuntu 13.04 64 Bit with Kernel 3.8.0-34-generic, shows an effective MTU of 552 at strong connections. But at the Gigabit-LAN setting a lower MTU, e. g. 256, works. So MTUs lower than 552 can be faked but are not always faked.

For the measurements with pings it is necessary that the connection does not drop the pings because of other traffic; the connection must not be fully loaded.

The lower MTU limit of the linux kernel is 256 Byte, but under very bad conditions it may be usefull set a lower value, e. g. 128 or only 68. For this you have to go the kernel sources and edit net/mac80211/iface.c, function ieee80211_change_mtu. There you have to replace "< 256" by "< 68", compile and load the module mac80211 to make the change effective. But usually a MTU of 512 works well, so this tuning is usually not needed but worth a try for bad connections.

An other way of usinger smaller data packets is the frag option of iwconfig, "iwconfig frag ", which splits an IP packet in a burst of smaller fragments. The frag parameter sets the maximum fragment size in Bytes which is always lower than the maximum packet size. By default frag is "off" and the minimum with untuned Linux sources also 256.

3 Tuning the temperature

When i cool the WL0162 with a thermal pack to a case temperature of about 5°C i get 2 dBm more, about 60 % more Power, compared with the power at a room temperature of 20°C. And when the measurement starts with a cold adapter at room temperature, the waming up reduces the power by about 2.5 dBm, nearly 50 % in Milliwatt.
So good cooling or better ventilation or putting away the adapter from direct sunlight and warm places gives significan more power. At big adapters, e. g. the AWUS051NH, this effect is smaller because they have a smaller thermal resistance to the air.
A side effect of the cooling is that noise, e. g. thermal noise, is reduced and therefore the adapter should be more sensive, but the sensitivity depends on many factors and a temperature change changes many of them, not all in the direction of lower noise.
You can measure the sensitivity roughly by reading the level of an access point under several temperatures.
This tuning is independet from linux and not linear because for every adapter there is a maximum power temperature between room temperature (293 K) and zero (0 K). So cooling with liquid helium or nitrogen is surely not better than cooling with ice.
Another point is that the drivers usually do use a temperature compensation, so the temperature dependence of the power can be complicated.

cool WL0162
The picture above shows a WL0162 cooled by the USB powered 1.5 Euro, 5 V fan Sunon GB0545AFV1-8.
With the boosted driver this cooling additionally boosted the power from 493 mW = 26.9 dBm to 702 mW = 28.5 dBm, around 1.5 dB or in mW 43 % more, at 20°C room temperature.

4 Using individual adapter variations

I compared three WL0162 adapters and found variations of 2 dB, about 60 % more/less Power.
So if you have more than one adapter of one kind you have a good chance that you can select a "golden sample" which gives you significant more power than the average.
And it's the same with receiving: Some adapters are significant more sensitiv than the average, you see more WiFis and have a wider reception range with these adapters.

5 Tuning the driver

The driver often do not allow 100 % power, because of bugs, not implemented features, and other reasons like using only default or low values to assure the country regulations. So usually if you can't get the full power which is specified the most probable reason is a weak driver but you can change that by changing the souce code.
I've done this with the Ralink driver for the WL0162 (chipset RT3070L) and other adapters like the AWUS051NH (chipset RT2770 RT2750), by tuning the source drivers/net/wireless/rt2x00/rt2800lib.c, recompiling, unloading the old module and loading the new module rt2800lib, with rmmod/insmod rt2800lib.
For kernel 3.8.0-31 the original version is
here and the tuned version here.
With a comparing program like kompare you can see the tuning changes and transfer them to future versions of rt2800lib.c. Befor you compare with a future verson you should indent it with "indent --k-and-r-style --no-tabs", to filter irrelevant differences.

For automatisation of the tuning via the kernel sources i made this script.

With the original driver under Ubuntu 13.04 i had an output power of 182 mW = 22.6 dBm, with the tuned 493 mW = 26.9 dBm, which is about 4 dBm more and also the power specified in the data sheet.
So tuning the countrycode and the driver changed the output power from 86 mW = 19.3 dBm to 493 mW = 26.9 dBm, about five times more power, only by software changes, without other tuning actions.

6 Tuning the rate

Changing the rate does not change the power explicitly but implicitly, so that at higher rates a lower power is used and this is specified in the WiFi standards. So the TX power rate is the power rate for the lowest bit rate, 1 Mbit/s, and at higher bit rates lower.
For the WL0162 the table of data rates and (maximum) transmit power is:
11n (13.5 - 150 Mbps): 20 ± 1dBm
11g     (6 - 54 Mbps): 22 ± 1dBm
11b     (1 - 11 Mbps): 27 ± 2dBm
The table of other adapters are similar.
Another point is that lowering the rate increaeses the sensitiv, also specified in the data sheets of WiFi adapters.
For the WL0162 the table of data rates and receive sensitivity is:
11n / 130 Mbps:  -75dBm
11g /  54 Mbps:  -76dBm
11b /  11 Mbps:  -95dBm
11b /   1 Mbps: -101dBm 
One reason is that the thermal noise increases with the channel bandwidth and that for higher rates greater bandwidths are used.
So a lower rate gives more power AND more sensitivity. The result is better stability, e. g. less packet loss, and a wider transmission and reception range.
Because the lowest rate is usually enough for me i simply use "iwconfig <device> rate 1M auto" in my WiFi script to automatically connect to free a WiFi to set the rate to 1 Mbit/s. But this is only the local transmission rate. The other side can use an other rate and i can see that e. g. at an Netgear WG602 v3 with DD-WRT v24-sp2 which uses an Auto rate of 24 or 36, and the rate or SNR of the client does not influence the rate of the router.
If you need more you can try higher rates, e. g. 2, 5.5, 6, 6.5, 9, 11, 12, 13, 18, 24, 36, 48, 54, 78, 81, 104, 108, 117, 121.5, 135, 150, 162, 216, 243, 270, 300 or higher. But setting the rate works only if the device is up (ifconfig <device> up).
In theory the command "iwlist <device> rate" shows you all availible rates but for my WL0162 and several other adapters the output is "wlan0 no bit-rate information.".
But "iw list" shows the availble (non-HT) rates up to 54M and many other capabilities.

If you have a good signal to noise ratio or strong signal you need no tuning of the rate and can set the rate to auto (iwconfig <device> rate auto). This sets to a rate higher than 1M, e. g. 39M or 43.3M and from time to time it changes between these two rates, which gives a stable connection. It is possible to set a higher rate, e. g. 54M, but often that does not enable a stable connection and often such a rate can not be set.

The iwconfig command shows the current rate, but after an inactivity of about one minute the rate drops to 1M, gets increases to the previous value before by activity and iwconfig updates the rate information only after activity, e. g. a ping.
So to find out the rates wich are possible with the current adapter and access point you can look at the rates the iwlist which "iwlist s" schows or you an use use:
rm -f /tmp/foobar.rate*; for i in $(seq 1 300); do iwconfig wlan0 rate "$i"M fixed; sleep 1; ping -W 1 -q -c 3 2>&1 >/dev/null; echo -n $i; iwconfig wlan0 | grep Rate | tee -a /tmp/foobar.rate.txt; done; cat /tmp/foobar.rate.txt | cut -d "=" -f2 | cut -d " " -f1 | sort -V | unique /tmp/foobar.rate_.txt; cat /tmp/foobar.rate_.txt
This example with wlan0 is for an AP which may have a rate up to 300 Mbit/s and has the IP
This method also finds non-integer rates like 5.5.
The following examples where made with the adapter Centrino Advanced-N 6235, 802.11 a/b/g/n, a distance of 2 m and under Ubuntu 13.04.
Example 1: Netgear WG602 v3, 2.4 GHz band, rates    1, 2, 5.5, 6,           9, 11, 12,           18,             24,           36,           48,     54
Example 2: Belkin F6D6230-4 v1, 2.4 GHz band, rates 1, 2,      6,           9, 11, 12,           18,             24,           36,           48,     54
Example 3: Belkin F6D6230-4 v1, 5 GHz band, rates              6, 6.5,      9,     12, 13,       18,             24,           36,           48,     54,             65
The last example was made with an AWUS036NEH: 
Example 4: Belkin F6D6230-4 v1, 2.4 GHz band, rates 1, 2,      6, 6.5, 7.2, 9, 11, 12,     14.4, 18, 19.5, 21.7, 24, 26, 28.9, 36, 39, 43.3, 48, 52, 54, 57.8, 58.5, 65, 72.2
So the Belkin router and the adapters in theory can use rates up to 150M or 300M, but the highest availble (65) is less then one half.
Higher rates of 130M and 144.4M where possible with a really short distance of only one meter and parallel orientation (to the two antennas of the Belkin F6D6230-4 v1).

A simple monitoring of the rate can be done with a loop:
typeset -i i=0; while true; do iwconfig 2>&1 | grep Rate | cut -d "=" -f2 | cut -d " " -f1 | tr -d "\n"; echo -e "\t$i"; i=i+1; sleep 1; done

A simple and rough measurement of the availible rate can be done with a flooding ping, e. g.
nice --20 ionice -c2 -n0 ping -W 1 -q -c 300 -l 3 -s 65507 -p 0f1e2d3c4b5a6978 -f
This works with APs which replys pings, so with most APs. Alternatives are Downloading from an HTTP or FTP server and tools like iperf.
The measured rate is number_of_packets * brutto_packet_size/time.
Example with the nominal rate 1M: 30 * 65535 Byte /15.021 s = 130.9 kByte/s = 1.05 Mbit/s, and 895.5 Mb/s for gigabit ethernet LAN (1000 Mb/s nominal). For rates higher than 11M the measured rate is about half the nominal value, e. g. 12.72 Mb/s at 24M.
But with such big packets of 65536 byte size the packet loss is usually 100 %, so this measures only the sending bandwidth without receiving. For measuring the bandwidth with (nearly) 0 % loss a smaller packet size must be used, e. g. 512 byte (including header and checksum):
ping -W 1 -q -c 15625 -s 484 -l 128 -p 0f1e2d3c4b5a6978 -f
Because of low packet loss the measured rate is 2* number_of_packets * brutto_packet_size/time, with number_of_packets * brutto_packet_size = 8,000,000 Bytes in this example.

7 Tuning the MAC address

Many Organisations like NSA and Mafia do collect many data without asking, informing, paying and often illegal, so you generelly should use strong encryption and also faked data.
This does not change the power but increases privacy.
A little fake can be done with a random media access control address (MAC address, short MAC).
For this you can install the package macchanger from a repository and put some lines in the local boot script (/etc/rc.local under Debian based distributions):
# Set random MACs   
macchanger -r eth0
macchanger -r eth1
macchanger -A wlan0
If the WiFi device is up, you have to take it down first. Example: "ifconfig wlan0 down".
If you have no macchanger, e. g. in an embedded busybox Linux, you can use other commands, e. g.
# Set a random MAC. Because modern WIFI cards usually have higher bytes (numbers), this ensures another and random MAC.
ran=$(head /dev/urandom | md5sum)
ip link set dev wlan0 down
ip link set dev wlan0 address $MAC
ip link set dev wlan0 up
An other command to set the MAC is ifconfig. Example: "ifconfig wlan0 hw ether 4e:31:6f:83:88:f1".

At WiFi adapters changing the MAC is complicated, because many drivers, e. g. the one for the WL0162 under Ubuntu 13.04, do allow only changing the last three bits! Others, e. g. under Ubuntu 13.04 the driver for the Centrino Advanced-N 6235 and the one for the WL0162 under OpenSuSE 12.3, allow much more changes but not all valid MACs.
So the only portable way to set a random other MAC is to start changing the last three bits, set this new MAC, changing another bit group and try to set that new MAC and so on. Because kernel and driver do check and refuse to set an invalid MAC like 00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff there is no need to check the random MACs.
This algorithm ensures at least a random change in the last three bits and more if the driver allows more.
If you start this procedure with the permanent MAC of the adapter, the new random MAC is always different from the permanent MAC, really randomized.

The permanent MAC can be displayed via macchanger. Example: "macchanger -s wlan0" displays the permanent and current MAC. The similar command "macchanger -p wlan0" resets the MAC address to its original, permanent hardware value.
The algorithm above, with starting with the permanent MAC and toggling of the bits, is implemented in my WiFi script to automatically connect to free a WiFi.
That script additionally assures that the new MAC is not equal to the MAC of another network adapter.
A description can be found here.

It is usefull to use a random MAC at any network interface and modem, because there ist usually no need to use the original MAC and when you use a cable modem you usually must change the MAC of the connected computer or router to get a new IP address.

8 Further tuning

A good source for the capabilities of the WiFi adapter is the output of "iw list".
At embedded computers, e. g. a WiFi router, the tuning is more complicated because the operating system, often a busybox Linux, is small and has not many options. But some options can be used via the integrated web server, e. g. the transmission power (TX power) at DD-WRT under Wireless -> Advanced Settings -> TX Power, and Wireless -> Advanced Settings -> Afterburner.

A WiFi connection has many parameters and most of them can be tuned. You can find them in the man pages for iwconfig and other commands.
One example is rts handshaking for less packet loss by doing a handshake with the AP to guarantee that it is listening: iwconfig wlan0 rts 1.
An other example for less packet loss is to increase the retry level because normally your WiFi adapter gives up after seven attempts at sending a packet. 15 or 30 is often better: iwconfig wlan0 retry 30.
An other parameter is the mode of the access point: Mixing modes decreases the performance, so generelly only one mode (e. g. 802.11g instead of 802.11b+g, 802.11n instead of 802.11b+g+n) should be used .

There are many other methods for WiFi tuning which are independent from Linux, like channel filters, boosters, choosing a WiFi channel, shielding, directional antennas, antenna diversity and low loss WiFi cables.
The WiFi cables should be as short as possible because a cable causes attenuation.
The number of WiFi connectors should be as low as possible because a connector causes attenuation and signal reflection, in total a loss of about 0.5 dB per connector.
Internal/integrated antennas are a less-than-ideal solution because of their small size and characteristic, so WiFi adapters with an external antenna (with nut inserts) should be prefered.

A significant factor for the RF power is the damping/electrical resistance of the USB cable to the adapter because a cheap and medium long 3 m USB2 cable with medium thin power cables one power cable has a resistance of about 0.65 ohm. So the adapter at the end is connectet to the 5 V of the PC or hub with a significant resistance of 1.3 ohm. When the adapter takes a current of 400 mA the voltage at the adapter is only 5 V - 1.3 * 0.4 V = 4.48 V, so this cable causes more than 10 % voltage and DC power loss. This causes also a loss in the RF power of about the same value. Therefore short USB cables or cables with thick power cables should be prefered, e. g. USB3 cables because USB3 has a higher current specification. The cables can be compared via their AWG values and the power conductors should have 24 AWG (or better, e. g. 22 AWG).
When you use a hub it should not be bus powered, because such a passive hub reduces the output voltage, USB standard conform down to only 4.0 V. When you use an USB hub with an power input you can boost the voltage to 5.25 V to get about more power. You can use more voltage and 5.5 V should be no problem but more than 5.25 V is outside the USB standards.
The voltage/current can be monitored cheap with a USB voltage current meter, e. g. an "CHARGER Doctor" with an internal consumption of 20 mA, via Ebay from China for about 3 Euro.
With the WL0162 with the fan i could measure 4.49 V behind a passive USB3 hub and 1.5 m USB3 cable. At this voltage the RF power was 689 mW = 28.4 dBm. After increaesing the voltage at the WL0162 with a PSU to 5.50 V, which is +22.5 % more, the RF power was increased to 889 mW = 29.4 dBm, which is +31.4 % more, 1 dBm more.
More voltage also increases the sensitivity: By increasing the voltage from 5.03 to 6.19 V the number of neighbour WiFis which iwlist finds increases from 10-11 to 12-13 and the levele of most WiFis is increased by about 7.
Therefore an USB cable with an integrated and tunable or set to 5.5 V step-up converter for boosting the supply voltage would be a good idea, but there is none at the market.

A simple tuning via hardware is the polarisation: Nearly everyone uses vertical antennas and therefore vertical polarisation, because it's easy. It's often not easy to use horizontal polarisation, but when you use it you see a) less WiFis from the neighbourhood and b) the WiFis from the neighbourhood much weaker. This is simple polarisation filtering. The effekt is that the WiFis from the neighbourhood do distort your WiFi much less and you have a better connection, e. g. a better signal to noise ratio and often you can set a higher rate.


WLAN Leistungsmessungen