Nice links. My wife has an iPhone 11 with iOS 16 and iPad Pro 12 and in our network with 3x RT3200s using WPA2-PSK and 802.11r she experiences things like when she unlocks her phone the WiFi symbol shows connected but she actually doesn't get internet connectivity until she disables and re-enables WiFi. I don't know how to fix this but would love to try out any suggestions.
For example, might trying WPA3-SAE with roaming help?
FWIW, I have ~20 Apple devices (Intel MacBooks, M1 MacBook, iPhones, iPads, Apple Watches, etc) that happily migrate between my 3x RT3200s without any loss of connectivity requiring manual intervention. I chose the word "migrate" specifically to avoid labeling it "roaming" for fear that confounds the syntax with mixed 802.11r support on the client level.
My 3x RT3200s (dumb APs) are ethernet connected back to a core switch where I have multiple VLANs supplied to the APs for multiple SSIDs.
I'm not saying my configuration is perfect, but I can say without a doubt I am not having the issue you described. Here is a snippet of my wireless config. I omitted all of the SSIDs I have configured because they effectively duplicate what I show here.
As you can see my config is super simple. Any idea what setting I should try from your config as you have a lot of extra settings set? It may be significant that my RT3200's are connected to each other via WDS.
I am trying to think what out of your settings might be the most significant. For example what about 'ieee80211w'? Or ' 'wnm_sleep_mode'?
Interesting! One thing I've noticed is that not all Apple devices are affected by that bug. An iPad 5th gen I have roams without issues, and an iPhone 8 that used to be in the household roamed just fine too. The bug got introduced at a later point it seems.
Just out of curiosity, none of your system logs contain long roam attempts like mine here?
Roam log
Sun Feb 26 17:02:04 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:04 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:04 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:04 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
Sun Feb 26 17:02:19 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:19 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:19 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:19 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
Sun Feb 26 17:02:33 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:33 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:33 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:33 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:02:45 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:45 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:45 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:45 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:02:56 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:56 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:56 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:56 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
Sun Feb 26 17:02:59 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:02:59 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:02:59 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:02:59 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:03:55 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:03:55 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:03:55 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:03:55 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:04:28 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:04:28 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:04:28 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:04:28 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:04:30 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:04:30 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:04:30 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:04:30 2023 daemon.debug hostapd: phy0-ap0: STA 0e:84:ea:0b:b3:37 MLME: MLME-AUTHENTICATE.indication(0e:84:ea:0b:b3:37, FT)
Sun Feb 26 17:04:46 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:04:46 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:04:46 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:04:46 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
Sun Feb 26 17:04:48 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:04:48 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:04:48 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:04:48 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
Sun Feb 26 17:04:51 2023 daemon.err hostapd: nl80211: kernel reports: key addition failed
Sun Feb 26 17:04:51 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: binding station to interface 'phy0-ap0'
Sun Feb 26 17:04:51 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 IEEE 802.11: authentication OK (FT)
Sun Feb 26 17:04:51 2023 daemon.debug hostapd: phy0-ap0: STA 66:d8:12:d5:a0:02 MLME: MLME-AUTHENTICATE.indication(66:d8:12:d5:a0:02, FT)
I understand that's a good idea because mine are fairly close together. This setting change from '0' didn't seem to affect this issue for me.
All '8'. Are they supposed to be different? I don't actually know what the significance of this feature is actually.
Seems like I should switch to 'HT20'. Presumably that's also slightly higher range as well owing to greater power concentration over narrower bandwidth.
This seems like it could be major. What do 802.11k and 802.11v do I wonder? Do they help roaming?
Perhaps someone else can weigh in on whether BSS color only applies to differentiating between transmissions on identical base stations using the same frequency.
Yes, they're quite significant. Here is the Apple link that explains the purposes of them: https://support.apple.com/en-us/HT202628. There are certainly other sources outside of Apple that explain them as well.
Indeed--per the Usteer setup link I posted previously, I assume many readers (including myself initially) miss this important note:
Note: On previous versions of OpenWrt, the config option “bss_transition” used to be called “ieee80211v”. If migrating from an older version, please update this config-option too!
I have had really good success with Usteer (as opposed to Dawn). Here is how I have Usteer configured:
Usteer Config
config usteer
# The network interface for inter-AP communication
option 'network' 'lan'
# Log messages to syslog (0/1)
option 'syslog' '1'
# Disable network communication (0/1)
option local_mode '0'
# Use IPv6 for remote exchange
option 'ipv6' '0'
# Minimum level of logged messages
# 0 = fatal
# 1 = info
# 2 = verbose
# 3 = some debug messages
# 4 = network packet information
# 5 = all debug messages
option 'debug_level' '2'
# Maximum number of neighbor reports set for a node
#option max_neighbor_reports 8
# Maximum amount of time (ms) a station may be blocked due to policy decisions
#option sta_block_timeout 30000
# Maximum amount of time (ms) a local unconnected station is tracked
#option local_sta_timeout 120000
# Maximum amount of time (ms) a measurement report is stored
#option measurement_report_timeout 120000
# Local station information update interval (ms)
#option local_sta_update 1000
# Maximum number of consecutive times a station may be blocked by policy
#option max_retry_band 5
# Maximum idle time of a station entry (ms) to be considered for policy decisions
#option seen_policy_timeout 30000
# Minimum number of stations delta between APs before load balancing policy is active
#option load_balancing_threshold 0
# Minimum number of stations delta between bands before band steering policy is active
#option band_steering_threshold 5
# Interval (ms) between sending state updates to other APs
#option remote_update_interval 1000
# Number of remote update intervals after which a remote-node is deleted
#option remote_node_timeout 10
# Allow rejecting assoc requests for steering purposes (0/1)
option assoc_steering 1
# Allow ignoring probe requests for steering purposes (0/1)
#option probe_steering 0
# Minimum signal-to-noise ratio or signal level (dBm) to allow connections
#option min_connect_snr 0
# Minimum signal-to-noise ratio or signal level (dBm) to remain connected
#option min_snr 0
# Timeout after which a station with snr < min_snr will be kicked
#option min_snr_kick_delay 5000
# Timeout (ms) for which a client will not be steered after rejecting a BSS-transition-request
#option steer_reject_timeout 60000
# Timeout (in ms) after which a association following a disassociation is not seen
# as a roam
#option roam_process_timeout 5000
# Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger
# client scans for roaming
#option roam_scan_snr 0
# Maximum number of client roaming scan trigger attempts
#option roam_scan_tries 3
# Retry scanning when roam_scan_tries is exceeded after this timeout (in ms)
# In case this option is set to 0, the client is kicked instead
#option roam_scan_timeout 0
# Minimum time (ms) between client roaming scan trigger attempts
#option roam_scan_interval 10000
# Minimum signal-to-noise ratio or signal level (dBm) before attempting to trigger
# forced client roaming
#option roam_trigger_snr 0
# Minimum time (ms) between client roaming trigger attempts
#option roam_trigger_interval 60000
# Timeout (ms) for client roam requests. usteer will kick the client after this times out.
#option roam_kick_delay 10000
# Minimum signal strength difference until AP steering policy is active
#option signal_diff_threshold 0
# Initial delay (ms) before responding to probe requests (to allow other APs to see packets as well)
#option initial_connect_delay 0
# Enable kicking client on excessive channel load (0/1)
#option load_kick_enabled 0
# Minimum channel load (%) before kicking clients
#option load_kick_threshold 75
# Minimum amount of time (ms) that channel load is above threshold before starting to kick clients
#option load_kick_delay 10000
# Minimum number of connected clients before kicking based on channel load
#option load_kick_min_clients 10
# Reason code on client kick based on channel load (default: WLAN_REASON_DISASSOC_AP_BUSY)
#option load_kick_reason_code 5
# Attempting to steer clients to a higher frequency-band every n ms.
# A value of 0 disabled band-steering.
#option band_steering_interval 120000
# Minimal SNR or absolute signal a device has to maintain over band_steering_interval to be
# steered to a higher frequency band
#option band_steering_min_snr -60
# Interval (ms) the device is sent a link-measurement request to help assess
# the bi-directional link quality. Setting the interval to 0 disables link-measurements.
#option link_measurement_interval 30000
# Script to run after bringing up a node
#option node_up_script ''
# Message types to include in log
# Available types:
# - probe_req_accept
# - probe_req_deny
# - auth_req_accept
# - auth_req_deny
# - assoc_req_accept
# - assoc_req_deny
# - load_kick_trigger
# - load_kick_reset
# - load_kick_min_clients
# - load_kick_no_client
# - load_kick_client
# - signal_kick
#list event_log_types ''
# List of SSIDs to enable steering on
list ssid_list '<redacted SSID 1>'
list ssid_list '<redacted SSID 2>'
list ssid_list '<redacted SSID 3>'
The most significant modification from OOB settings (outside of adding your SSIDs to the ssid_list is this:
It seems from reading like I should set bss_color to 1, 2 and 3 for my 3x AP's (5.4Ghz only, since 2.4 on RT3200 doesn't support AX). This ought to be helpful because they all operate on same frequency given my use of WDS. Does that seem correct to you?
I forgot about your APs being on the same channel due to WDS! My understanding is that you would be correct in setting the BSS color of each AP to a unique number. This seems even more beneficial in your case than mine given my APs are all on different channels.
BSS Coloring is a new provision that allows devices operating in the same frequency space to quickly distinguish between packets from their own BSS and packets from an Overlapping BSS (OBSS), by simply looking at the BSS color value contained in the HE PHY header. In some scenarios, Spatial Reuse allows devices, to transmit at the same time as the OBSS packets they receive, instead of deferring transmissions because of legacy interference thresholds. Since every Wi-Fi 6 device understands the BSS color, it can be leveraged to increase power savings by dropping packets earlier, and to identify spatial reuse opportunities.
BSS Coloring is a method used to differentiate between the BSS of access points and their clients on the same RF channel. Wi-Fi 6 enables each AP radio to assign a value (from 1 to 63), known as BSS color, to be included in the PHY header of all HE transmissions from devices in its BSS. With devices of each BSS transmitting a locally-unique color, a device can quickly and easily distinguish transmissions coming from its BSS from those of a neighboring BSS.
With all that said, I'm not sure exactly how this relates specifically to WDS. I am not a WDS expert. Might be a question better addressed by experts like @nbd.