A Tale of Two Eduroams

A few years back the wireless team at UiT elected to make our eduroam service 5GHz only. The rationale was a cost/benefit assessment – the benefit of three extra 20MHz channels to carry traffic wasn’t worth the effort of providing them. Especially in student villages, where legacy rogue APs and uncontrollable interference sources abound. Added complexity in troubleshooting was another card on the table.

We decided that we would offer an inferior eduroam service for the benefit of 2.4GHz-only equipment, on a separate SSID, but sharing resources with “the real eduroam” on the wired side (VLANs and IP address space). But unfortunately, techies as we are, we picked a neutral and technologically oriented name for the SSID: eduroam-2.4GHz. A name that probably created no associations whatsoever with our wifi byod  users. In retrospect we should have picked something that sounded like the smell of fish rotting in the sun!

The consequence of our unlucky choice was that many users with dual-radio devices configured profiles for both eduroam and eduroam-2.4GHz, probably to improve the odds of finding a network to connect to. And we were no better off than if we’d just established the eduroam SSID on both bands in the first place.

Fast forward to the present:

This fall Apple introduced private MAC addresses in their operating systems. Each SSID that the device connects to is presented a unique MAC address. From the perspective of the wifi infrastructure, these addresses are used to identify and communicate with the devices. If a device presents two MAC addresses, then it’s considered to be two different devices as far as “the wifi” is concerned. And each MAC address is given a separate IP address. Which means that whenever the device roams between our two eduroam SSIDs, the active applications on the device have their operational IP address changed.

Many applications can cope with that. If your web browser fetches a page with one IP address, and the next page with another, that’s usually fine. But if your AV streaming application has it’s IP address changed beneath it’s networking interface, then it’s going to fall. Hard.

The timinig couldn’t be worse. Corona has brought a proliferation of digital meetings and distance lectures. Any student with both eduroams configured on their laptop risks five-minute unscheduled transmission breaks in knowledge transfer from their professor. And Murphy will ensure that those five minutes will be the most exam relevant of the semester.

Now we’re in the process of changing the name of our “inferior” eduroam on the 2.4GHz band, to something that our users will hesitate to select. Being an academic institution we couldn’t make it like fish rotting in the sun. It’s going to be lowQualityUnstable-eduroam.

(Before writing this, I searched for similar experiences or descriptions. The closest I found was this piece of advice: “Also, consider the impact of a per-SSID randomized MAC if corporate IT devices connect to more than one SSID” in https://www.extremenetworks.com/extreme-networks-blog/wi-fi-mac-randomization-privacy-and-collateral-damage/)


Tuning AP Transmit Power in Dense Areas, Motivation and Methodology

Tuning AP Transmit Power in Dense Areas

Motivation and Methodology

In this context, “dense areas” should be read as “rooms with more than one AP”. Wifi clients in dense area will select one of these nearby APs for association, and they should ideally distribute evenly across the APs, to achieve optimal utilization of the available resources, and minimum contention.

“Sticky client” is a well known term among wifi professionals. As is the concept of rooms with multiple APs, where one of them is installed close to the entrance. Without incentives to roam, many clients will stick to the entrance AP, and the other APs will be under-utilized. I have observed similar skew in client distribution in other dense environments.

The current best practise in wifi design suggests that directional antennas should be used in many of these rooms. In reality that isn’t always the case, for several reasons. You could have a large-ish room with regular ceiling height, where directional antennas would need very wide angles to cover the designated number of seats. Possibly so wide that the scenario is only marginally distinguishable from APs with built-in omnis. Or you could have an auditorium with a legacy wifi installation. Even though the APs may be upgraded from the original installation, upgrade budgets don’t always include money for wifi redesign and new cabling.

This is an attempt to investigate to what extent (static) power level adjustments can counter-act uneven AP utilization in dense areas.


Channel utilization would seem to be the best criterion to monitor, as the basis for power level control: all APs should operate on a channel with the same util% as their neighbors. But this is a very dynamic measure, laden with time resolution issues. The same goes for fps, Bps, MCS or retry rate. Having clients roam between APs based on any of these values seems impractical. In comparison, number of clients per (5GHz) radio is better suited for use as a control indicator: more stable, easily measurable, and relevant.

The selected monitoring strategy observes (counts 5GHz clients) in all dense areas 20 minutes past the hour, during business hours. This point in time is 5 minutes past lecture start, when the users/students/attendees should have settled, and the wifi clients should overall have made any roaming decision. If the wifi client count is at least 80% of seat capacity, I assume that the users have spread evenly across the room: the room is considered “full”, and client count is monitored every three minutes for all 5GHz radios, throughout the lecture.

The actual client counting is cron based, and uses my apclients script, which I presented in Prague in October 2019. E.g. output from “apclients -m mh-U6-012-01-rw” might look like:

mh-U6-012-01-rw  2  (5,21)

This interprets to an AP with 2 radios, having 5 and 21 associated clients respectively. Other options/flags may be used to determine which channel the radios operate on, and hence their frequency. Output is sorted and graphed, as e.g. for Tabletten auditorium.

PS. Cisco offers a load balancing feature, to limit the number of clients that are allowed to associate to an AP concurrently.  If max client count is exceeded, the AP responds to association requests with a refusal (initially), which introduces delays in the process.  Concensus is that this feature should not be used on latency-sensitive WLANs. For other WLANs, it should be enabled only after testing.

PPS. Currently “the gathering part” of the educational system in Norway has been suspended, due to the Corona virus – from kindergarden to universities.  So there will be no users in “my” auditoriums for some time. Nothing to count, no basis for adjustments, and no more cases to report.

Wi-Fi extensions to Speedtest

At WLPC in Prague I presented some scripts I’ve written to collect client data from Cisco WLCs via SNMP. A handful of people have asked for more details regarding one of my use cases: providing and logging connection data when a user runs speedtest from a Wi-Fi client.

How it’s done

When the user clicks the start button, the speedtest server picks up the client’s IP address and sends it in a UDP packet to a Wi-Fi lookup server, which uses my scripts to retrieve data from the wireless LAN controlllers. This data is returned to the speedtest server, and forwarded to the client browser as part of the normal speedtest response.

There’s some additional details, like what happens if the client is connected via cable, and syslog’ing of test results, but I’ll assume that’s below the noise floor. Look it up in the code or try it out if you’re interested. Or ask.

The code

The speedtest server extension (PHP code) is written by an ex-colleague of mine (who can contact me if he wants his name here), and inherits its license from the speedtest application (GPL). The Wi-Fi lookup code in Perl is mine, and it’s GPL’ed too.

The source code available here.


  1. The APtools scripts must be installed  and capable of retrieving data from Cisco WLCs. Copy the two additional Perl scripts into the same directory as aplist/apuser/apclients.
  2. Verify that lookups work locally, based on client IP address
  3. The PHP files are aligned with the speedtest version on the WLAN Pi. If that’s your speedtest server platform, copy them to /var/www/html/
  4. Adjust the speedtest files to your environment (see below).
  5. Adjust the Wi-Fi lookup files to your environment (ditto).


Determine a UDP port which gets through from your speedtest server to the Wi-Fi lookup server. In my environment the default 23456/udp is blocked by firewall/ACL, so I settled for 53/udp instead. Which is what DNS uses. Not very nice, I know.

Also, to use a port <1024 the Wi-Fi lookup server must be started as root. If that’s the case for you, change $suUser in speedtesterWiFiLookupSrv.pl from ‘wifimgr’ to a user that actually exists on the host.

conf_settings:php: change to the host and port of your Wi-Fi lookup server.

speedtest_worker.js: you may want to change getIp_ispInfo from ‘true’ to ‘false’ in line 52.

– in line 55-58 you may want to insert the paths as prefixes to the external programs
– change the reg.exp in line 65 (sub accessAllowed{…}) to the IP address of your speedtest server, i.e. /^(MY.IP.ADD.RESS)$/

And GO!

Start “speedtesterWiFiLookupSrv.pl rcvPort=yourUDPport debug=on”, and begin by verifying that the UDP packets flow from the speedtest server host to Wi-Fi lookup server and back. To do that, determine the IP address of a Wi-Fi client and use nc(1) in a terminal window with your server and port:
wlanpi@wlanpi: echo WI.FI.CLIENT.IP |nc -u lookupSrv lookupPort

If you get something back it should work with speedtest too.

Good luck!