Getting started with WiFi development
Part 3: Debugging

The FreeBSD WiFi stack is amenable to interrogation.

Tom Jones

In a series on starting WiFi development, the debugging part easily could have been the first, second, and third sections and we might never have looked at driver code.

WiFi has all the features that make debugging difficult: It is a concurrent distributed state machine; temporal physical and random effects change how things behave; it integrates the black magic of microwave RF design; and the hardware is proprietary, undocumented and unintuitive to use.

With all that said, FreeBSD has high performance WiFi and many people have contributed to driver and stack support over the last two decades, mostly in their spare time.

In the end, people work on WiFi because many of the debugging stages can be very satisfying once you start to make progress.

In this article we will look at two approaches to debugging WiFi on FreeBSD for driver development: passive packet capture and system logging.

Packet capture gives you an external view of the system. You can run capture on a third computer to get an understanding of what is happening (or isn’t) between your AP and station. It can give a ground truth on what data has crossed the network independent of driver effects.

System logging gives us an insight into what FreeBSD thinks is happening based on the packets it has seen. Packets and events are logged at many places and we can see how traffic causes changes in the state machine. We can see what happens to traffic which passed on the air interface but disappeared once it went to the FreeBSD machine.

 

First pass Debugging

First let us start with common issue-focused debugging .

I think for most people when it comes to debugging WiFi they are wondering why their station cannot join a network. In most cases failure to join the network is going to be due to something really straightforward to find, and it usually feels like a silly mistake.

If you get the PSK wrong for a wpa network, wpa_supplicant will suggest to you that is the problem:



<3>Trying to associate with 94:83:c4:58:ed:32 (SSID='o2-enc' freq=2437 MHz)

<3>Associated with 94:83:c4:58:ed:32

<3>CTRL-EVENT-DISCONNECTED bssid=94:83:c4:58:ed:32 reason=0

<3>WPA: 4-Way Handshake failed - pre-shared key may be incorrect

<3>CTRL-EVENT-SSID-TEMP-DISABLED id=8 ssid="o2-enc" auth_failures=1 duration=10 reason=WRONG_KEY

<3>Added BSSID 94:83:c4:58:ed:32 into ignore list, ignoring for 10 seconds

<3>CTRL-EVENT-SCAN-RESULTS

 

This example is the output of the wpa_cli tool. It gives you a direct interface to wpa_supplicant logs and all.

Typing the wrong key can’t be solved by any tool, but generating the correct entry can be solved by using wpa_passphrase to generate a new entry.



$ wpa_passphrase "example network" "excellentpsk"

network={

   ssid="example network"

   #psk="excellentpsk"

   psk=27231323cedae4b8036557f8dcd5f38bfb6e0ac9a5ab894a4ee5104f7998fc93

}

 

Other issues when trying to join the network might be due to range or the card not seeing beacons advertising the network’s presence. In the past, when you only had one device, this was difficult to figure out. But now we almost always have another WiFi device that can verify that the network does in fact work here, suggesting that it is something up with the configuration on the FreeBSD device.

The second type of problems people want to debug are performance issues. Either the network doesn’t reach to where you want it to, or there is a configuration issue leading to less performance than you expected, based on using other systems on the same network.

This is much harder to figure out and fewer people are going to be able to help. You probably don’t know what is inside your walls and no stranger on the Internet is going to be able to make a good guess at what is going wrong. They can however help by looking at the symptoms.

Thankfully it isn’t just mystical radio issues that lower performance, and there is some configuration and investigation you can do to help improve network speeds wpa_cli is a great first place to look when trying to figure out which networks we can actually see:



> scan_results

bssid / frequency / signal level / flags / ssid

c8:e3:06:4d:1d:83       2437    -81     [RSN-SAE-CCMP][MESH]    19c14

c8:e3:06:5d:3d:48       2437    -81     [WPA2-PSK-CCMP][ESS]    Computer Network

18:e8:b9:c2:18:1a       2412    -87     [WPA2-PSK+SAE-CCMP][ESS]        HomeWifi

a8:e3:06:5d:fd:47       2437    -81     [ESS]

20:12:34:c6:18:bd       2412    -87     [ESS]   Guest-Wifi

 

The scan_results command displays the current networks that wpa_supplicant knows about. It gets these from the driver it is bound to via the net80211 subsystem. If you are trying to join a network but it can’t be seen here, then you might be out of luck. Try moving closer to the AP if you can and gradually walk away until signal drops off.

If you are tracing a performance issue then your first stop should be looking at the receive signal strength indicator (RSSI). If the signal level is too low then you now know that the device isn’t near enough to the access point. Signal level is reported in dBm. This will always be negative. As a relative measure, this means the closer it is to 1, the higher the strength. A very low just-detectable signal will be about ~87dBm, and a high signal might be about 50dBm. Many protocol features are restricted to the signal strength being a certain level.

The other configuration issue that might be limiting performance can be very difficult to debug. WiFi uses radio spectrum in a variety of bands. In some places this is all free to use for WiFi devices, but in other parts of the world WiFi might be a secondary user of the spectrum. This blocks out some bands for use. And in some parts of the world weather radar detection must be performed in the 5GHz band.

The collection of bands and their availabilities are called a regulatory domain. If there is a mismatch between the regulatory domain of the station and the access point, you might find that the device is limited to using older WiFi standards.

A mismatch can occur for many reasons. If you use your ISP-provided wireless router, then it should be configured correctly for where you are. But you might have bought a device from a vendor who doesn’t know to which regdomain it is going, or you might take a travel router with you. In that case you should verify matching regulatory domains between the station, the access point, and neighbouring access points. Yes, it is possible that someone else’s access point is configured wrong, or differently and the firmware in your station’s card decides it is in a different part of the world.

You can check the stations regdomain with ifconfig:



$ ifconfig wlan0

wlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500

             options=0

             ether 74:da:38:33:c0:62

             groups: wlan

             ssid "" channel 10 (2457 MHz 11g)

             regdomain FCC country US authmode WPA1+WPA2/802.11i privacy MIXED

             deftxkey UNDEF txpower 30 bmiss 7 scanvalid 60 protmode CTS wme

             roaming MANUAL bintval 0

             parent interface: rtwn0

             media: IEEE 802.11 Wireless Ethernet autoselect (autoselect)

             status: no carrier

             nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

 

Out of the box FreeBSD has put my mostly unconfigured rtwn device into the US regdomain:



regdomain FCC country US authmode WPA1+WPA2/802.11i privacy MIXED

ifconfig can also be used to check the regdomain of access points it can see, though the output is quite difficult to read:



$ ifconfig -v wlan0 scan results

SSID/MESH ID                      BSSID              CHAN RATE    S:N     INT CAPS

HomeWifi                          18:e8:b9:c2:18:1a    1   54M  -87:-95   100 EPS  SSID<HomeWifi> RATES<B2,B4,B11,B22,12,18,24,36> DSPARMS<1> COUNTRY<GB  1-13,20> ERP<0x0> RSN<v1 mc:AES-CCMP uc:AES-CCMP km:8021X-PSK+?> XRATES<48,72,96,108> BSSLOAD<sta count 3, chan load 56, aac 18> RRM_ENCAPS<460573d000000c> HTCAP<cap 0x1ac param 0x1b mcsset[0-15] extcap 0x0 txbf 0x0 antenna 0x0> HTINFO<ctl 1, 8,4,0,0 basicmcs[]> OVERLAP_BSS<4a0e14000a002c01c8-> EXTCAP<7f080500000200000040> WME<qosinfo 0x0 BE[aifsn 3 cwmin 4 cwmax 10 txop 0] BK[aifsn 7 cwmin 4 cwmax 10 txop 0] VO[aifsn 2 cwmin 3 cwmax 4 txop 94] VI[aifsn 2 cwmin 2 cwmax 3 txop 47]> ATH<0x7fff> VEN<dd3900156d00010100010217e5810618e8-> VEN<dd168cfdf0040000490000030209720100-> VEN<dd088cfdf00101020100>

 

The COUNTRY element in the caps field at the end of the scan shows where the access point thinks it is:


COUNTRY<GB  1    -13,20>

 

The solution to this is to specify the regulatory domain and country with ifconfig:



$ ifconfig wlan0 list countries

 

Country codes:

DEBUG Debug        ZW Zimbabwe        YE Yemen           VN Viet Nam      

VE Venezuela       UZ Uzbekistan      UY Uruguay         US United States  

GB United Kingdom  AE United Arab Emi UA Ukraine         TR Turkey        

TN Tunisia         TT Tobago          TH Thailand        TW Taiwan        

SY Syria           CH Switzerland     SE Sweden          LK Sri Lanka      

ES Spain           ZA South Africa    SI Slovenia        SK Slovak Republic

SG Singapore       SA Saudi Arabia    RU Russia          RO Romania        

QA Quatar          PR Puerto Rico     PT Portugal        PL Poland        

PH Phillipines     PE Peru            PA Panama          PK Pakistan      

OM Oman            NO Norway          NZ New Zealand     NL Netherlands    

NP Nepal           MA Morocco         MC Monaco          MX Mexico        

MT Malta           MY Malaysia        MK Macedonia       MO Macau          

LU Luxemborg       LT Lithuania       LI Liechtenstein   LB Lebanon        

LV Latvia          KW Kuwait          K2 Korea Republic2 KR Korea Republic

KP North Korea     KZ Kazakhstan      JO Jordan          J5 Japan5        

J4 Japan4          J3 Japan3          J2 Japan2          J1 Japan1        

JP Japan           JM Jamaica         IT Italy           IL Israel        

IE Ireland         IR Iran            ID Indonesia       IN India          

IS Iceland         HU Hungary         HK Hong Kong       HN Honduras      

GT Guatemala       GR Greece          DE Germany         GE Georgia        

F2 France2         FR France          FI Finland         EE Estonia        

SV El Salvador     EG Egypt           EC Ecuador         DO Dominican Repub

DK Denmark         CZ Czech Republic  CY Cyprus          HR Croatia        

CR Costa Rica      CO Colombia        CN China           CL Chile          

CA Canada          BG Bulgaria        BN Brunei          BR Brazil        

BO Bolivia         BZ Belize          BE Belgium         BY Belarus        

BD Bangladesh      BH Bahrain         AZ Azerbaijan      AT Austria        

AU Australia       AM Armenia         AR Argentina       DZ Algeria        

AL Albania        

Regulatory domains:

XC900M          GZ901           XR9             SR9            

NONE            ROW             TAIWAN          KOREA          

APAC3           APAC2           APAC            ETSI3          

ETSI2           ETSI            JAPAN           FCC4          

FCC3            FCC             DEBUG          

 

$ sudo ifconfig wlan0 down

$ sudo ifconfig wlan0 country GB regdomain ETSI

 

Packet Capture

Generating a packet capture (or a pcap) can be a helpful debugging step when you want to understand the traffic which is going over the air and the WiFi interface. A wlan interface in FreeBSD can generate pcaps at two levels, as the logical Ethernet device similar to if you used a wired interface such as em and at the link layer giving you access to the 80211 packet types. The first is what you will get when an interface is configured as a station, but a wlan interface in monitor mode will give you more information about the underlying link.

Back in part 1 of this series we created three different VAPs (virtual access points) for our example hardware, station, host AP, and monitor mode.

A monitor mode VAP puts the underlying hardware into a promiscuous mode where all packets are received and fed to bpf with the link headers intact . This gives more link information as well as all the packets that can be heard on a channel, rather than those directed towards the device or the broadcast address.

In the driver, all packets can be tagged with information about the radio environment that were received, this is put in a field called the radio tap header.

 

The radiotap header tells us useful metadata about the state of the WiFi radio when the packet was received, things such as the receive strength (RSSI), the WiFi channel and the modulation. These fields can be key in understanding why (or more often why not) something is working.

In monitor mode we get all the packets the radio can receive. This itself can lead to a lot of clues about what is happening in the local rf environment.

 

tcpdump

There are two tools to use when debugging WiFi using packet captures and tcpdump is key in getting information with minimal overhead. tcpdump is a standard packet capture tool and ships in FreeBSD base.

Normally tcpdump shows us packet information at the ip layer with a little introspection to look at what packets are doing. To get full advantage on a WiFi interface we need to ask tcpdump to include link layer headers and specifically IEEE802_11_RADIO.


# ifconfig wlan create wlandev rtwn0 wlanmode monitor

 

With WiFi headers included, we no longer have a view into the traffic but we get a lot of additional fields describing the radio environment and information about the mac layer of ieee80211.



$ sudo tcpdump -i wlan0 -y IEEE802_11_RADIO

tcpdump: data link type IEEE802_11_RADIO

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode

listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes

10:27:07.724396 74143272us tsft 1.0 Mb/s 2437 MHz 11g -32dBm signal -95dBm noise Beacon (o2-enc) [1.0* 2.0* 5.5* 11.0* 9.0 18.0 36.0 54.0 Mbit] ESS CH: 6, PRIVACY

10:27:07.938361 74362602us tsft 6.0 Mb/s 2437 MHz 11g -58dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:07.953755 74375625us tsft 6.0 Mb/s 2437 MHz 11g -58dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:07.958151 74382377us tsft 11.0 Mb/s 2437 MHz 11g -68dBm signal -95dBm noise Beacon () [1.0* 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0 Mbit] ESS CH: 6

10:27:07.973090 74394982us tsft 6.0 Mb/s 2437 MHz 11g -58dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:08.003137 74424986us tsft 6.0 Mb/s 2437 MHz 11g -58dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:08.007497 74432483us tsft 6.0 Mb/s 2437 MHz 11g -59dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:08.033133 74454986us tsft 6.0 Mb/s 2437 MHz 11g -61dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:08.037498 74462485us tsft 6.0 Mb/s 2437 MHz 11g -59dBm signal -95dBm noise Clear-To-Send RA:e0:3e:44:08:34:e1 (oui Unknown)

10:27:08.063204 74486734us tsft 11.0 Mb/s 2437 MHz 11g -68dBm signal -95dBm noise Data IV:d43 Pad 20 KeyID 1

10:27:08.063206 74486734us tsft 11.0 Mb/s 2437 MHz 11g -68dBm signal -95dBm noise Data IV:d44 Pad 20 KeyID 1

10:27:08.063211 74486734us tsft 11.0 Mb/s 2437 MHz 11g -68dBm signal -95dBm noise Data IV:d45 Pad 20 KeyID 1

10:27:08.063211 74486734us tsft 11.0 Mb/s 2437 MHz 11g -68dBm signal -95dBm noise Data IV:d46 Pad 20 KeyID 1

 

When you run the above command, you are likely to be flooded with management (mgmt) traffic from local stations. To continue we need to think back to the WiFi session establishment process we discussed in previous articles.

In the previous article we talked about how a station joins a network, in summary it:

–       probes for the network    (probe request, response)

–       authenticates             (auth request, response)

–       associates                (assoc request, response)

 

Each of these stages is two different mgmt frames: a request and a response. But these are probably not even the frames you are being flooded with!

To speed up the network joining process and to give clients a list of networks to join, all access points ‘beacon’ their existence constantly. In a very busy environment beacons might use up a lot of the available airtime, that long list of available WiFi networks isn’t really a good thing.

Beacon frames carry a lot of information about the network and its capabilities, we can filter to only see beacon frames in the tcpdump capture like so:


10:27:07.724396 74143272us tsft 1.0 Mb/s 2437 MHz 11g -32dBm signal -95dBm noise Beacon (o2-enc) [1.0* 2.0* 5.5* 11.0* 9.0 18.0 36.0 54.0 Mbit] ESS CH: 6, PRIVACY

 

There is a lot more information in a beacon than tcpdump will show you on its own, to get more of the data carried by the beacon we need to switch to using wireshark or in this case its command line interface tshark.

First we can pull out a pcap using tcpdump:


$ sudo tcpdump -i wlan0 -y IEEE802_11_RADIO -w testcaputre.pcap -c 1000

 

We can feed our capture to tshark and ask it to show the first beacon packet for the test network we saw before:


$ tshark -V -r testcaputre.pcap -a "packets: 1" 'wlan.ssid == "o2-enc"'

 

This outputs nearly 900 lines of packet description for the 393 byte beacon frame, here is a small section showing the beacon frame and some radio information.



802.11 radio information

      PHY type: 802.11b (HR/DSSS) (4)

      Short preamble: False

      Data rate: 11.0 Mb/s

      Channel: 6

      Frequency: 2437MHz

      Signal strength (dBm): -66 dBm

      Noise level (dBm): -95 dBm

      Signal/noise ratio (dB): 29 dB

      TSF timestamp: 1853402918

      [Duration: 461µs]

             [Preamble: 192µs]

             [IFS: 15572µs]

             [Start: 1853402457µs]

             [End: 1853402918µs]

IEEE 802.11 Beacon frame, Flags: ........

      Type/Subtype: Beacon frame (0x0008)

      Frame Control Field: 0x8000

             .... ..00 = Version: 0

             .... 00.. = Type: Management frame (0)

             1000 .... = Subtype: 8

             Flags: 0x00

                    .... ..00 = DS status: Not leaving DS or network is operating in AD-HOC mode (To DS: 0 From DS: 0) (0x0)

                    .... .0.. = More Fragments: This is the last fragment

                    .... 0... = Retry: Frame is not being retransmitted

                    ...0 .... = PWR MGT: STA will stay up

                    ..0. .... = More Data: No data buffered

                    .0.. .... = Protected flag: Data is not protected

                    0... .... = +HTC/Order flag: Not strictly ordered

      .000 0000 0000 0000 = Duration: 0 microseconds

      Receiver address: Broadcast (ff:ff:ff:ff:ff:ff)

             .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)

             .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)

      Destination address: Broadcast (ff:ff:ff:ff:ff:ff)

             .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)

             .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)

      Transmitter address: GLTechnologi_58:ed:32 (94:83:c4:58:ed:32)

             .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)

             .... ...0 .... .... .... .... = IG bit: Individual address (unicast)

      Source address: GLTechnologi_58:ed:32 (94:83:c4:58:ed:32)

             .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)

             .... ...0 .... .... .... .... = IG bit: Individual address (unicast)

      BSS Id: GLTechnologi_58:ed:32 (94:83:c4:58:ed:32)

             .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)

             .... ...0 .... .... .... .... = IG bit: Individual address (unicast)

      .... .... .... 0000 = Fragment number: 0

      1010 0010 1011 .... = Sequence number: 2603

      [WLAN Flags: ........]

 

System Logs

The third source of information for debugging WiFi issues comes via system tools and logs. Most of the time the system aims to be relatively quiet. In the messages it prints, we normally only get those printed for exceptional conditions such as errors. Developers like to bake in the option of live system debugging and we can increase debugging levels and fill up the kernel message buffer with lots of juicy facts about the WiFi stack.

 

wlandebug


/usr/sbin/wlandebug

 

FreeBSD ships the wlandebug(8) tool which gives a friendlier interface to configuring the verbosity of prints that come from the net80211 stack.


# wlandebug -i wlan1 scan+auth+assoc

 

Messages are printed directly to the kernel buffer which can be annoying when you want to track events as they come. We can display these newly printed messages with dmesg.



$ dmesg

wlan0: ieee80211_scanreq: vap 0xfffff80139506000 iv_state 0x1 (SCAN) flags 0x20052 duration 0x7fffffff mindwell 0 maxdwell 0 nssid 1

wlan0: ieee80211_check_scan: active scan, append, nojoin, once

wlan0: ieee80211_swscan_start_scan_locked: active scan, duration 2147483647 mindwell 0 maxdwell 0, desired mode auto, append, nojoin, once

wlan0: scan set

1g, 6g, 11g, 7g, 2g, 3g, 4g, 5g, 8g, 9g, 10g                              

wlan0:  dwell min 20ms max 200ms                                          

wlan0: scan_curchan_task: loop start; scandone=0, scanstop=0, ss_iflags=0x2, ss_next=0, ss_last=11

wlan0: scan_curchan_task: chan   6n ->   1g [active, dwell min 20ms max 200ms]

wlan0: scan_curchan: calling; maxdwell=200                                

wlan0: scan_curchan_task: waiting                

[22:e8:29:c7:48:1a] new probe_resp on chan 1 (bss chan 1) "Guest-Wifi" rssi 15

[22:e8:29:c7:48:1a] caps 0x1421 bintval 100 erp 0x100 country [GB  1-13,20]

wlan0: ieee80211_swscan_add_scan: chan   1g min dwell met (2167162969 > 18446744071581747289)

wlan0: scan_mindwell: called

wlan0: scan_curchan_task: loop start; scandone=0, scanstop=0, ss_iflags=0x21, ss_next=1, ss_last=11

wlan0: scan_curchan_task: chan   1g ->   6g [active, dwell min 20ms max 200ms]

wlan0: scan_curchan: calling; maxdwell=200

wlan0: scan_curchan_task: waiting        

[c8:e3:06:5d:fd:45] new probe_resp on chan 6 (bss chan 6) 0x48c3a47474652c2048c3a47474652c204661687261646b65747465 rssi 29

[c8:e3:06:5d:fd:45] caps 0x1431 bintval 100 erp 0x100 country [GBI 1-13,20]

[c8:e3:06:5d:fd:45] new probe_resp on chan 6 (bss chan 6) 0x48c3a47474652c2048c3a47474652c204661687261646b65747465 rssi 29

[c8:e3:06:5d:fd:45] caps 0x1431 bintval 100 erp 0x100 country [GBI 1-13,20]

[c8:e3:06:5d:fd:45] new probe_resp on chan 6 (bss chan 6) 0x48c3a47474652c2048c3a47474652c204661687261646b65747465 rssi 29

[c8:e3:06:5d:fd:45] caps 0x1431 bintval 100 erp 0x100 country [GBI 1-13,20]

wlan0: ieee80211_swscan_add_scan: chan   6g min dwell met (2167162992 > 18446744071581747312)

wlan0: scan_mindwell: called

[c8:e3:06:5d:fd:45] new probe_resp on chan 6 (bss chan 6) 0x48c3a47474652c2048c3a47474652c204661687261646b65747465

wlan0: scan_curchan_task: loop start; scandone=0, scanstop=0, ss_iflags=0x21, ss_next=2, ss_last=11 rssi 29

wlan0: scan_curchan_task: chan   6g ->  11g [active, dwell min 20ms max 200ms]

[c8:e3:06:5d:fd:45] caps 0x1431 bintval 100 erp 0x100 country [GBI 1-13,20]

wlan0: scan_curchan: calling; maxdwell=200

wlan0: scan_curchan_task: waiting

wlan0: scan_curchan_task: loop start; scandone=0, scanstop=0, ss_iflags=0x20, ss_next=3, ss_last=11

wlan0: scan_curchan_task: chan  11g ->   7g [active, dwell min 20ms max 200ms]

wlan0: scan_curchan: calling; maxdwell=200                                

wlan0: scan_curchan_task: waiting                                        

 

These messages are controlled by a mask on a per device sysctl. We could set this manually, but wlandebug gives us a nice interface for doing so. Once configured we get additional log messages on the system log, which we can recover using the dmesg command.

Each message which is printed is by the IEEE80211_DPRINTF kernel macro.

The final messages in our example come from scan_curchan and in the source they look like this:



IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,

      "%s: calling; maxdwell=%lu\n",

      __func__,

      maxdwell);

 

IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN,

      "%s: loop start; scandone=%d, scanstop=%d, ss_iflags=0x%x, ss_next=%u, ss_last=%u\n",

      __func__,

      scandone,

      scanstop,

      (uint32_t) ss_priv->ss_iflags,

      (uint32_t) ss->ss_next,

      (uint32_t) ss->ss_last);

 

wlandebug enables you to take advantage of the debugging statements built into the kernel without having to do a rebuild or be overloaded with output messages all the time.

wlanstat

Collects stats using the SIOCG80211STATS ioctl. Inside net80211 these are stored in the vap iv_stats member which is an instance of ieee80211_stats a ~150 member struct tracking what has happened in the wlan stack.

Thankfully wlanstat is smart about what it prints and it will only display statistics with relevant information:



$ wlanstat                                                  

1821              rx from wrong bssid

2                 rx discard mgt frames

2127              rx beacon frames

17629             rx element unknown

53                rx frame chan mismatch

5                 active scans started

18                ccmp crypto done in s/w

2221              rx management frames

2                 rx action frames

59                A-MSDU frames received

3                 A-MPDU frames discarded for out of range seqno

5034              total data frames received

5016              unicast data frames received

18                multicast data frames received

6044              total data frames transmit

6044              unicast data frames sent

58.5M             current transmit rate

31.5              current rssi

-95               current noise floor (dBm)

-63.5             current signal (dBm)

 

From wlanstat we get some historic and current information. The current information at the end of the output shows us the signal strength, noise floor and current transmit rates. These will vary as we move and based on how much traffic we have sent recently.

The historic information tells us about the types of frames we have seen. One useful stat for debugging is the number of A-MSDU frames we have received. This number being low can be a great indicator as to why aren’t able to achieve higher throughput rates.

ifconfig

ifconfig can tell you a lot of information about how the wlan interface is configured.



$ ifconfig -v wlan0

wlan0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500

      options=0

      ether 74:da:38:33:c0:62

      groups: wlan

      ssid "" channel 1 (2412 MHz 11b) bssid 00:00:00:00:00:00

      regdomain FCC country US anywhere -ecm authmode OPEN -wps -tsn

      privacy OFF deftxkey UNDEF

      powersavemode OFF powersavesleep 100 txpower 30 txpowmax 50.0 -dotd

      rtsthreshold 2346 fragthreshold 2346 bmiss 7

      11b     ucast NONE    mgmt  1 Mb/s mcast  1 Mb/s maxretry 6

      11g     ucast NONE    mgmt  1 Mb/s mcast  1 Mb/s maxretry 6

      11ng    ucast NONE    mgmt  1 Mb/s mcast  1 Mb/s maxretry 6

      scanvalid 60 -bgscan bgscanintvl 300 bgscanidle 250

      roam:11b     rssi    7dBm rate  1 Mb/s

      roam:11g     rssi    7dBm rate  5 Mb/s

      roam:11ng    rssi    7dBm  MCS  1    

      -pureg protmode CTS ht20 htcompat ampdu ampdulimit 64k

      ampdudensity 16 amsdu shortgi htprotmode RTSCTS -puren -smps -rifs

      -stbc -ldpc -uapsd -vht wme -burst -dwds roaming AUTO bintval 0

      AC_BE cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm ack

              cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm

      AC_BK cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm ack

              cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm

      AC_VI cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm ack

              cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm

      AC_VO cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm ack

              cwmin  0 cwmax  0 aifs  0 txopLimit   0 -acm

      parent interface: rtwn0

      media: IEEE 802.11 Wireless Ethernet autoselect (autoselect)

      status: no carrier

      nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

      drivername: wlan0

 

The verbose ifconfig output tells us a lot of practical information about how the wlan interface is configured and the network and channel it is on (if it is on a network, in this example the ssid is blank as we aren’t connected to anything).

The ifconfig output tells us parameters we can tune such as the tx power, country, and regdomain.
It also contains parameters we pick up from the network we are on.
The AC_BE, AC_BK, AC_VI, and AC_VO describe access class parameters advertised by the network in management frames.

Applying tools

There is a lot of information available from the FreeBSD WiFi stack to help you debug issues, but I think the reality for most people is that you will quickly be overwhelmed with technical details. In most cases, you will get more immediate value starting with higher level tools and working down. If you are having trouble connecting to a network, then running wpa_cli and taking note of the messages it reports will leave you in the best standing. If the underlying device is configured correctly and the Access Point is in range, then your problems are most likely to be addressed with advice from wpa_supplicant.

If you suspect that the net80211 layer or device driver is the problem, then your next course of action will be the two-pronged approach of verifying the traffic on the air with packet captures and validating the behaviour of net80211. This takes more understanding of how WiFi works, but it can be a good place to get clues about what is wrong.

It is easy to jump at shadows and think that a field indicates an error that isn’t there. My main piece of advice to take from this article and the series is how amenable to interrogation the FreeBSD WiFi stack is. If you want to debug a problem, then reaching out to the mailing lists is a great step. You might be asked to present debugging information such as some of the things discussed here.

This shouldn’t be scary. It is quite straightforward to enable most of the available logging mechanisms and all of them will default to off again if you reboot.

The speeds and performance we can get with WiFi is incredible, it has grown from a 1Mbit/s link up to more than a gigabit and most of the time we get very consistent results. Our WiFi stack is always improving and with more users and testing it will get better.


Tom Jones is a FreeBSD committer interested in keeping the network stack fast.