Proper configuration of 802.11k and 802.11v

Continuing this discovery... I confirmed that without Usteer or Dawn, beacon frames from the AP do not have Link Measurement enabled. This screen capture is what the beacon looks like when Usteer or Dawn are enabled (I tested with each enabled independently):

And the beacon without either Usteer or Dawn:

1 Like

Any thoughts on this:

In yet another interesting twist, I found an older iPhone 7 which is running iOS 15.7.3. It actually sends a Neighbor Report Request:

However, the AP does not reply with a Neighbor Report Response.

I have a single Android device (not by choice) in my house and it properly exchanges Neighbor Report Requests and Neighbor Report Responses with my APs.

Is this an iOS issue? Does Apple not use NRRs anymore?

In relation to my previous post, I have submitted a bug report with Apple to make them aware of what I am seeing. Not going to hold my breath on getting actionable responses back, but they may surprise me.

3 Likes

Here is a question, mindful that both DAWN and Usteer have various snags. Perhaps @patrakov, @account4538 or @eR2022 can offer some insight.

Would you expect enabling 802.11k and 802.11v without doing anything else to cause harm? If so why? And what minimum extra step(s) should be undertaken to make things work well with having enabled 802.11k and/or 802.11v? For example, above there was mention of static-neighbor-report.

No harm in enabling any of these options by themselves.

Here is a DAWN config that works for me with WPA2 - but note that this is just a test setup, and I don't really need the second AP. The test clients are two Linux laptops with Intel AX200 and AX210 cards, and Samsung Galaxy A02 phone. I know that there are lots of options that should better be removed.

And note: this has been tested on the 2.4 GHz only, as band steering inevitably adds latency spikes while in the gray area. I could not get 802.11r to work reliably - sometimes it does roam with FT, sometimes it does a full 4-way handshake.

/etc/config/wireless fragment on Linksys E8450
config wifi-device 'radio0'
	option type 'mac80211'
	option path 'platform/18000000.wmac'
	option band '2g'
	option country 'PH'
	option htmode 'HT40'
	option channel '13'
	option noscan '1'
	option local_pwr_constraint '0'
	option cell_density '1'
	option txpower '20'
	option log_level '1'

config wifi-iface 'wifinet5'
	option device 'radio0'
	option mode 'ap'
	option ssid 'Backbone'
	option encryption 'psk2+ccmp'
	option wds '1'
	option key 'PASSWORD'
	option ieee80211w '2'
	option wpa_disable_eapol_key_retries '1'
	option network 'lan'
	option ieee80211r '1'
	option mobility_domain 'af15'
	option ft_psk_generate_local '0'
	option bss_transition '1'
	option wnm_sleep_mode '1'
	option time_advertisement '2'
	option time_zone 'GMT0'
	option ieee80211k '1'
	option ft_over_ds '0'
	option reassociation_deadline '20000'
/etc/config/wireless fragment on Netgear WAX202 (used as a repeater)
config wifi-device 'radio0'
	option type 'mac80211'
	option path '1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0'
	option band '2g'
	option country 'PH'
	option noscan '1'
	option htmode 'HT40'
	option channel '13'
	option cell_density '1'
	option txpower '20'
	option log_level '1'

config wifi-iface 'wifinet1'
	option device 'radio0'
	option mode 'sta'
	option ssid 'Backbone'
	option bssid 'EA:9F:80:D4:9E:C5'
	option key 'PASSWORD'
	option wds '1'
	option encryption 'psk2+ccmp'
	option ieee80211w '2'
	option network 'lan'

config wifi-iface 'wifinet2'
	option device 'radio0'
	option mode 'ap'
	option ssid 'Backbone'
	option encryption 'psk2+ccmp'
	option wds '1'
	option key 'PASSWORD'
	option ieee80211r '1'
	option mobility_domain 'af15'
	option ft_psk_generate_local '1'
	option ieee80211w '2'
	option wpa_disable_eapol_key_retries '1'
	option network 'lan'
	option bss_transition '1'
	option wnm_sleep_mode '1'
	option time_advertisement '2'
	option time_zone 'GMT0'
	option ieee80211k '1'
	option ft_over_ds '0'
	option reassociation_deadline '20000'
/etc/config/dawn, identical on both devices
config local
	option loglevel '1'

config network
	option broadcast_ip '192.168.10.255'
	option broadcast_port '1025'
	option tcp_port '1026'
	option network_option '2'
	option shared_key 'PASSWORDpassword'
	option iv 'PASSWORDpassword'
	option use_symm_enc '1'
	option collision_domain '-1'
	option bandwidth '-1'

config hostapd
	option hostapd_dir '/var/run/hostapd'

config times
	option con_timeout '60'
	option update_client '10'
	option remove_client '15'
	option remove_probe '30'
	option remove_ap '460'
	option update_hostapd '10'
	option update_tcp_con '10'
	option update_chan_util '5'
	option update_beacon_reports '20'

config metric 'global'
	option min_probe_count '2'
	option bandwidth_threshold '0'
	option kicking_threshold '10'
	option min_number_to_kick '3'
	option use_station_count '0'
	option max_station_diff '1'
	option eval_probe_req '0'
	option eval_auth_req '0'
	option eval_assoc_req '0'
	option deny_auth_reason '1'
	option deny_assoc_reason '17'
	option chan_util_avg_period '3'
	option duration '150'
	option set_hostapd_nr '2'
	option rrm_mode 'apt'
	option kicking '1'

config metric '802_11g'
	option initial_score '70'
	option ht_support '0'
	option vht_support '0'
	option rssi '0'
	option low_rssi_val '-80'
	option low_rssi '-15'
	option chan_util '0'
	option max_chan_util '0'
	option rssi_weight '1'
	option no_ht_support '0'
	option no_vht_support '0'
	option rssi_val '-60'
	option chan_util_val '140'
	option max_chan_util_val '170'
	option rssi_center '-50'

config metric '802_11a'
	option initial_score '100'
	option ht_support '0'
	option vht_support '0'
	option rssi '0'
	option low_rssi_val '-80'
	option low_rssi '-15'
	option chan_util '0'
	option max_chan_util '-15'
	option no_ht_support '0'
	option no_vht_support '0'
	option rssi_val '-60'
	option chan_util_val '140'
	option max_chan_util_val '170'
	option rssi_weight '1'
	option rssi_center '-70'

The key for reliable kicking was to enable active probing.

1 Like

Thanks for posting that config!

How do you test? I found the android phone app Ubiquiti WiFiman app helpful because it shows you transitions in real-time with continuously plotting graph of signal strength. I haven't figured out a good alternative for Apple iPhones or iPads. Or perhaps with DAWN you can look in the DAWN logs.

The motivation behind my question was just that it seems nice to be able to be able to keep things simple. I think that was perhaps @account4538's approach.

I also test using that, but also note that it produces some false reports about roaming. I.e. it draws an arrow without the word "Disconnected", while in the hostapd log on the AP there is clearly a 4-way handshake.

Screenshot falsely indicating a successful roam but also a huge latency spike:

Hostapd log on the target AP, clearly indicating that FT did not work this time:

Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.11: authentication OK (open system)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c MLME: MLME-AUTHENTICATE.indication(c8:51:42:23:d4:0c, OPEN_SYSTEM)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c MLME: MLME-DELETEKEYS.request(c8:51:42:23:d4:0c)
Wed Mar  8 09:00:28 2023 daemon.info hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.11: authenticated
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.11: association OK (aid 1)
Wed Mar  8 09:00:28 2023 daemon.info hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.11: associated (aid 1)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c MLME: MLME-ASSOCIATE.indication(c8:51:42:23:d4:0c)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c MLME: MLME-DELETEKEYS.request(c8:51:42:23:d4:0c)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.11: binding station to interface 'wlan0-1'
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: event 1 notification
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: start authentication
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.1X: unauthorizing port
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: sending 1/4 msg of 4-Way Handshake
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: received EAPOL-Key frame (2/4 Pairwise)
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: sending 3/4 msg of 4-Way Handshake
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: received EAPOL-Key frame (4/4 Pairwise)
Wed Mar  8 09:00:28 2023 daemon.notice hostapd: wlan0-1: AP-STA-CONNECTED c8:51:42:23:d4:0c
Wed Mar  8 09:00:28 2023 daemon.debug hostapd: wlan0-1: STA c8:51:42:23:d4:0c IEEE 802.1X: authorizing port
Wed Mar  8 09:00:28 2023 daemon.info hostapd: wlan0-1: STA c8:51:42:23:d4:0c RADIUS: starting accounting session D6904079BFEF1D64
Wed Mar  8 09:00:28 2023 daemon.info hostapd: wlan0-1: STA c8:51:42:23:d4:0c WPA: pairwise key handshake completed (RSN)
Wed Mar  8 09:00:28 2023 daemon.notice hostapd: EAPOL-4WAY-HS-COMPLETED c8:51:42:23:d4:0c
Wed Mar  8 09:00:38 2023 daemon.notice hostapd: wlan0-1: BEACON-REQ-TX-STATUS c8:51:42:23:d4:0c 32 ack=1
Wed Mar  8 09:00:54 2023 daemon.notice hostapd: wlan0-1: BEACON-REQ-TX-STATUS c8:51:42:23:d4:0c 33 ack=1
Wed Mar  8 09:00:58 2023 daemon.notice hostapd: wlan0-1: BEACON-REQ-TX-STATUS c8:51:42:23:d4:0c 34 ack=1
Wed Mar  8 09:01:00 2023 cron.err crond[1769]: USER root pid 25360 cmd scp root@192.168.10.1:/tmp/dhcp.leases /tmp/dhcp.leases.new && mv /tmp/dhcp.leases.new /tmp/dhcp.leases
Wed Mar  8 09:01:14 2023 daemon.notice hostapd: wlan0-1: BEACON-REQ-TX-STATUS c8:51:42:23:d4:0c 35 ack=1
1 Like

You can test if 802.11k neighbor report is working by checking to see if the neighbor list is populated:

ubus call hostapd.wlan1 rrm_nr_list (or wlan0, wlan1-1, etc...)

I only use the neighbor report and 802.11r fast transition and both Apple and Android phones FT without issue and I don't have any devices that cannot connect.

I'm using WPA2-PSK, no 802.11w frame protection, KRACK countermeasures off, reassociation deadline 65535, FT over the air, generate PMK locally, and Time interval for rekeying GTK=0

1 Like

Thanks. Couple more questions.

Do you use static-neighbor-report to make that work? If not how do you populate the list? And might static-neighbor-report not be a good idea in your case?

Why not? What's your thinking behind this?

How I'm doing it is I'm populating the list in startup and as a cronjob. static-neighbor-report and other scripts do the same thing for you.

After populating the list, it will remain until a reboot or change in settings where hostapd has to restart. So I just do a check every 5 mins to make sure the list is still populated which is what those scripts do, but you can do it with a one line command.

To get the info from an AP:
ubus call hostapd.wlan1 rrm_nr_get_own (or wlan0, wlan1-1, etc...)

Just put this info into it's neighboring AP - example:

ubus call hostapd.wlan1 rrm_nr_set '{"list": [["e3:44:52:13:c4:96","ssid_name","e3445213c496ef097000110d070603000f00"]]}'

In startup at least for my AP I need a sleep 4 first so hostapd is setup and radios are on.

As for cron, all you need is:

*/5 * * * * [[ "`ubus call hostapd.wlan1 rrm_nr_list`" == *","* ]] ||

before the command above.

Just for me it's just easier for the simplicity and management vs a script or package that is just a one line command.

As for 802.11v I just don't need it as my mobile devices roam fine without issue. I have also read that it can cause issues with 802.11r fast transition which was my main focus. If you have to force disconnect a device then you loose the fast transition and the device has to scan again and then completely re-authenticate to an AP and do the 4-way handshake. This breaks your connection and ruins the experience for the user especially if it's something like wifi calling, video chat, streaming video, etc. that they are on.

1 Like

@_FailSafe how about in this fine thread instead?

Quick update around the bug report I submitted to Apple. It is still unacknowledged in their system. Not surprising, but I will keep checking on it as time goes by.

At least it hasn’t been closed automatically yet. :smiling_face:

Could you be convinced to share tips on using static-neighbor-reports?

Just following this since having looked into static-neighbor-reports I likewise prefer your manual approach. For anyone also implementing this, to add multiple AP's, just use the format:

ubus call hostapd.wlan1 rrm_nr_set '{"list": [["e3:44:52:13:c4:96","ssid_name","e3445213c496ef097000110d070603000f00"],["e3:44:52:13:c4:96","ssid_name","e3445213c496ef097000110d070603000f00"]]}'

Thank you, I forgot to mention that.

Also, I found out some AP config changes such as changing the channels changes that identifying string.

1 Like

I've just put together a service file for this purpose:

#!/bin/sh /etc/rc.common

exec &> /var/log/neighbor-reports.log

START=60
STOP=4

start()
{
        ubus call hostapd.wlan0 rrm_nr_set 

        ubus call hostapd.wlan0-1 rrm_nr_set 

        ubus call hostapd.wlan1 rrm_nr_set
}

stop()
{
        :
}

Perhaps hotplug event should be added? I'm not sure what it should trigger on though.

I'm not sure how with hotplug but a cronjob just simply checking for the existence of the neighbor list has been working flawlessly:

[[ "`ubus call hostapd.wlan1 rrm_nr_list`" == *","* ]]
1 Like

Ah yes, I see. Nice idea.

Also, is there any way to reasonably easily test that it's working in terms of what clients see?

“Reasonable” is quite subjective. If Wireshark doesn’t scare you away, what you’re seeking can be found in this post from above:

Just remember, with Apple devices you’re treading in territory for which I have the open bug report with Apple.

1 Like