Roaming switch time is around 120ms with WPA2-PSK

AP and client, both of them are based on X86 with ath10k driver.
AP installed OpenWrt. Client is Linux embedded machine, very powerful.

The key management is WPA-PSK, for sure the roaming has no issue, but roaming performance is not so good as what I expected.
The roaming switch time (from wpa_supplicant log) is around 120ms, normally should be 20 ~ 30ms.

However, if AP is using TP-link router with ath9k, client is same as above (same sw and configuration), the performance is good, around 30ms.
This is ath9k/10k driver issue or hardware issue ? I think x86 embedded machine is very powerful, it should have better performance than TP-link.

Are you using 802.11k/r/v (any or all of those)?

No, just traditional wpa-psk

Ok. Let’s see the configs from both devices.

Please copy the output of the following commands and post it here using the "Preformatted text </> " button:
grafik
Remember to redact passwords, MAC addresses and any public IP addresses you may have:

cat /etc/config/network
cat /etc/config/wireless
cat /etc/config/dhcp
cat /etc/config/firewall

AP1:

root@OpenWrt:~# cat /etc/config/network 

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fd45:b89d:a6d4::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option netmask '255.255.255.0'
	option ipaddr '192.168.10.60'

config interface 'wan'
	option device 'eth1'
	option proto 'dhcp'

config interface 'wan6'
	option device 'eth1'
	option proto 'dhcpv6'

root@OpenWrt:~# cat /etc/config/wireless 

config wifi-device 'radio0'
	option type 'mac80211'
	option path 'pci0000:00/0000:00:13.2/0000:07:00.0/0000:08:02.0/0000:0a:00.0'
	option cell_density '0'
	option country 'CA'
	option band '5g'
	option channel '36'
	option txpower '0'
	option htmode 'VHT20'
	option log_level '1'

config wifi-iface 'default_radio0'
	option device 'radio0'
	option network 'lan'
	option mode 'ap'
	option ssid 'OpenWrt'
	option encryption 'psk2'
	option key 'XXXXXXXX'
	option wmm '0'

root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
	option domainneeded '1'
	option boguspriv '1'
	option filterwin2k '0'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option nonegcache '0'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
	option nonwildcard '1'
	option localservice '1'
	option ednspacket_max '1232'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv4 'server'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	option ignore '1'
	option ra 'hybrid'
	option dhcpv6 'hybrid'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

root@OpenWrt:~# cat /etc/config/firewall 
config defaults
	option syn_flood	1
	option input		ACCEPT
	option output		ACCEPT
	option forward		REJECT
# Uncomment this line to disable ipv6 rules
#	option disable_ipv6	1

config zone
	option name		lan
	list   network		'lan'
	option input		ACCEPT
	option output		ACCEPT
	option forward		ACCEPT

config zone
	option name		wan
	list   network		'wan'
	list   network		'wan6'
	option input		REJECT
	option output		ACCEPT
	option forward		REJECT
	option masq		1
	option mtu_fix		1

config forwarding
	option src		lan
	option dest		wan

# We need to accept udp packets on port 68,
# see https://dev.openwrt.org/ticket/4108
config rule
	option name		Allow-DHCP-Renew
	option src		wan
	option proto		udp
	option dest_port	68
	option target		ACCEPT
	option family		ipv4

# Allow IPv4 ping
config rule
	option name		Allow-Ping
	option src		wan
	option proto		icmp
	option icmp_type	echo-request
	option family		ipv4
	option target		ACCEPT

config rule
	option name		Allow-IGMP
	option src		wan
	option proto		igmp
	option family		ipv4
	option target		ACCEPT

# Allow DHCPv6 replies
# see https://github.com/openwrt/openwrt/issues/5066
config rule
	option name		Allow-DHCPv6
	option src		wan
	option proto		udp
	option dest_port	546
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-MLD
	option src		wan
	option proto		icmp
	option src_ip		fe80::/10
	list icmp_type		'130/0'
	list icmp_type		'131/0'
	list icmp_type		'132/0'
	list icmp_type		'143/0'
	option family		ipv6
	option target		ACCEPT

# Allow essential incoming IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Input
	option src		wan
	option proto	icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	list icmp_type		router-solicitation
	list icmp_type		neighbour-solicitation
	list icmp_type		router-advertisement
	list icmp_type		neighbour-advertisement
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

# Allow essential forwarded IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Forward
	option src		wan
	option dest		*
	option proto		icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-IPSec-ESP
	option src		wan
	option dest		lan
	option proto		esp
	option target		ACCEPT

config rule
	option name		Allow-ISAKMP
	option src		wan
	option dest		lan
	option dest_port	500
	option proto		udp
	option target		ACCEPT


### EXAMPLE CONFIG SECTIONS
# do not allow a specific ip to access wan
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option dest		wan
#	option proto	tcp
#	option target	REJECT

# block a specific mac on wan
#config rule
#	option dest		wan
#	option src_mac	00:11:22:33:44:66
#	option target	REJECT

# block incoming ICMP traffic on a zone
#config rule
#	option src		lan
#	option proto	ICMP
#	option target	DROP

# port redirect port coming in on wan to lan
#config redirect
#	option src			wan
#	option src_dport	80
#	option dest			lan
#	option dest_ip		192.168.16.235
#	option dest_port	80
#	option proto		tcp

# port redirect of remapped ssh port (22001) on wan
#config redirect
#	option src		wan
#	option src_dport	22001
#	option dest		lan
#	option dest_port	22
#	option proto		tcp

### FULL CONFIG SECTIONS
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port	80
#	option dest		wan
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp
#	option target	REJECT

#config redirect
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port		1024
#	option src_dport	80
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp

AP2:

root@OpenWrt:~# cat /etc/config/network 

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fd06:6377:93ef::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.10.70'
	option netmask '255.255.255.0'
	option gateway '192.168.10.5'
	list dns '192.168.10.5'

config interface 'wan'
	option device 'eth1'
	option proto 'dhcp'

config interface 'wan6'
	option device 'eth1'
	option proto 'dhcpv6'

root@OpenWrt:~# cat /etc/config/wireless 

config wifi-device 'radio0'
	option type 'mac80211'
	option path 'pci0000:00/0000:00:13.2/0000:07:00.0/0000:08:03.0/0000:0b:00.0'
	option cell_density '0'
	option country 'CA'
	option htmode 'VHT20'
	option band '5g'
	option channel '36'
	option txpower '0'
	option log_level '1'

config wifi-iface 'default_radio0'
	option device 'radio0'
	option network 'lan'
	option mode 'ap'
	option ssid 'OpenWrt'
	option wmm '0'
	option encryption 'psk2'
	option key 'XXXXXXXX'

root@OpenWrt:~# cat /etc/config/dhcp

config dnsmasq
	option domainneeded '1'
	option boguspriv '1'
	option filterwin2k '0'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option nonegcache '0'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
	option nonwildcard '1'
	option localservice '1'
	option ednspacket_max '1232'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv4 'server'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	option ra 'hybrid'
	option dhcpv6 'hybrid'
	option ignore '1'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

root@OpenWrt:~# cat /etc/config/firewall 
config defaults
	option syn_flood	1
	option input		ACCEPT
	option output		ACCEPT
	option forward		REJECT
# Uncomment this line to disable ipv6 rules
#	option disable_ipv6	1

config zone
	option name		lan
	list   network		'lan'
	option input		ACCEPT
	option output		ACCEPT
	option forward		ACCEPT

config zone
	option name		wan
	list   network		'wan'
	list   network		'wan6'
	option input		REJECT
	option output		ACCEPT
	option forward		REJECT
	option masq		1
	option mtu_fix		1

config forwarding
	option src		lan
	option dest		wan

# We need to accept udp packets on port 68,
# see https://dev.openwrt.org/ticket/4108
config rule
	option name		Allow-DHCP-Renew
	option src		wan
	option proto		udp
	option dest_port	68
	option target		ACCEPT
	option family		ipv4

# Allow IPv4 ping
config rule
	option name		Allow-Ping
	option src		wan
	option proto		icmp
	option icmp_type	echo-request
	option family		ipv4
	option target		ACCEPT

config rule
	option name		Allow-IGMP
	option src		wan
	option proto		igmp
	option family		ipv4
	option target		ACCEPT

# Allow DHCPv6 replies
# see https://github.com/openwrt/openwrt/issues/5066
config rule
	option name		Allow-DHCPv6
	option src		wan
	option proto		udp
	option dest_port	546
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-MLD
	option src		wan
	option proto		icmp
	option src_ip		fe80::/10
	list icmp_type		'130/0'
	list icmp_type		'131/0'
	list icmp_type		'132/0'
	list icmp_type		'143/0'
	option family		ipv6
	option target		ACCEPT

# Allow essential incoming IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Input
	option src		wan
	option proto	icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	list icmp_type		router-solicitation
	list icmp_type		neighbour-solicitation
	list icmp_type		router-advertisement
	list icmp_type		neighbour-advertisement
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

# Allow essential forwarded IPv6 ICMP traffic
config rule
	option name		Allow-ICMPv6-Forward
	option src		wan
	option dest		*
	option proto		icmp
	list icmp_type		echo-request
	list icmp_type		echo-reply
	list icmp_type		destination-unreachable
	list icmp_type		packet-too-big
	list icmp_type		time-exceeded
	list icmp_type		bad-header
	list icmp_type		unknown-header-type
	option limit		1000/sec
	option family		ipv6
	option target		ACCEPT

config rule
	option name		Allow-IPSec-ESP
	option src		wan
	option dest		lan
	option proto		esp
	option target		ACCEPT

config rule
	option name		Allow-ISAKMP
	option src		wan
	option dest		lan
	option dest_port	500
	option proto		udp
	option target		ACCEPT


### EXAMPLE CONFIG SECTIONS
# do not allow a specific ip to access wan
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option dest		wan
#	option proto	tcp
#	option target	REJECT

# block a specific mac on wan
#config rule
#	option dest		wan
#	option src_mac	00:11:22:33:44:66
#	option target	REJECT

# block incoming ICMP traffic on a zone
#config rule
#	option src		lan
#	option proto	ICMP
#	option target	DROP

# port redirect port coming in on wan to lan
#config redirect
#	option src			wan
#	option src_dport	80
#	option dest			lan
#	option dest_ip		192.168.16.235
#	option dest_port	80
#	option proto		tcp

# port redirect of remapped ssh port (22001) on wan
#config redirect
#	option src		wan
#	option src_dport	22001
#	option dest		lan
#	option dest_port	22
#	option proto		tcp

### FULL CONFIG SECTIONS
#config rule
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port	80
#	option dest		wan
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp
#	option target	REJECT

#config redirect
#	option src		lan
#	option src_ip	192.168.45.2
#	option src_mac	00:11:22:33:44:55
#	option src_port		1024
#	option src_dport	80
#	option dest_ip	194.25.2.129
#	option dest_port	120
#	option proto	tcp

From client side log, it seems client was waiting for AP (access point) send back Authenticate Response.

16:26:41.792695   wpa_supplicant[1174]: WIFI1: Starting radio work 'sme-connect'@0x5603a72225f0 after 0.000027 second wait
16:26:41.794522   wpa_supplicant[1174]: WIFI1: State: COMPLETED -> AUTHENTICATING

//// here take most of time
16:26:41.909401   wpa_supplicant[1174]: nl80211: Drv Event 37 (NL80211_CMD_AUTHENTICATE) received for WIFI1
16:26:41.909401   wpa_supplicant[1174]: nl80211: Authenticate event
16:26:41.909401   wpa_supplicant[1174]: WIFI1: Event AUTH (10) received
16:26:41.910934   wpa_supplicant[1174]: nl80211: Association request send successfully
16:26:41.913747   wpa_supplicant[1174]: WIFI1: State: ASSOCIATING -> ASSOCIATED
16:26:41.914966   wpa_supplicant[1174]: WIFI1: State: ASSOCIATED -> 4WAY_HANDSHAKE
16:26:41.920959   wpa_supplicant[1174]: WIFI1: State: 4WAY_HANDSHAKE -> 4WAY_HANDSHAKE
16:26:41.920959   wpa_supplicant[1174]: WIFI1: State: 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
16:26:41.920959   wpa_supplicant[1174]: WIFI1: State: GROUP_HANDSHAKE -> COMPLETED
16:26:41.920959   wpa_supplicant[1174]: WIFI1: Radio work 'sme-connect'@0x5603a72225f0 done in 0.124389 seconds

From AP side log, most of time was taken after disconnect old STA, and received authentication notification from new STA.
Another one: after received 4 messages of handshake, it should be connected, but why still take around 80ms to print connected.
Is it normal ?

1686179305.307 wlan0: AP-STA-DISCONNECTED xx:xx:xx:xx:xx:xx

// why take 107ms authentication OK, this take most of time
1686179305.414 wlan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: authentication OK (open system)
1686179305.414 wlan0: STA xx:xx:xx:xx:xx:xx WPA: event 0 notification
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-AUTHENTICATE.indication(xx:xx:xx:xx:xx:xx, OPEN_SYSTEM)
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-DELETEKEYS.request(xx:xx:xx:xx:xx:xx)
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: authentication OK (open system)
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx WPA: event 0 notification
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-AUTHENTICATE.indication(xx:xx:xx:xx:xx:xx, OPEN_SYSTEM)
1686179305.415 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-DELETEKEYS.request(xx:xx:xx:xx:xx:xx)
1686179305.415 lan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: authenticated
1686179305.415 lan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: authenticated
1686179305.417 wlan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: association OK (aid 1)
1686179305.418 lan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: associated (aid 1)
1686179305.418 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-REASSOCIATE.indication(xx:xx:xx:xx:xx:xx)
1686179305.418 wlan0: STA xx:xx:xx:xx:xx:xx MLME: MLME-DELETEKEYS.request(xx:xx:xx:xx:xx:xx)
1686179305.418 wlan0: STA xx:xx:xx:xx:xx:xx IEEE 802.11: binding station to interface 'wlan0'
1686179305.418 wlan0: STA xx:xx:xx:xx:xx:xx WPA: event 1 notification
1686179305.419 wlan0: STA xx:xx:xx:xx:xx:xx WPA: sending 1/4 msg of 4-Way Handshake
1686179305.422 wlan0: STA xx:xx:xx:xx:xx:xx WPA: received EAPOL-Key frame (2/4 Pairwise)
1686179305.422 wlan0: STA xx:xx:xx:xx:xx:xx WPA: sending 3/4 msg of 4-Way Handshake
1686179305.424 wlan0: STA xx:xx:xx:xx:xx:xx WPA: received EAPOL-Key frame (4/4 Pairwise)

// why still take around 79ms
1686179305.503 wlan0: AP-STA-CONNECTED xx:xx:xx:xx:xx:xx
1686179305.503 wlan0: STA xx:xx:xx:xx:xx:xx IEEE 802.1X: authorizing port
1686179305.503 wlan0: STA xx:xx:xx:xx:xx:xx RADIUS: starting accounting session 5BA67CE7588B4D52
1686179305.503 wlan0: STA xx:xx:xx:xx:xx:xx WPA: pairwise key handshake completed (RSN)
1686179305.503 wlan0: EAPOL-4WAY-HS-COMPLETED xx:xx:xx:xx:xx:xx

Try using non-overlapping channels. Currently both devices are set to channel 36. For best performance, each AP should be on its own channel.

Tried, basically same, no improvement,

what channels are you using now?

I am not familiar with those channels, I just configured different channel from LuCi, AP1: 5180 AP2: 5785

Is it OK? For 2 APs, what channel do you prefer to use?

Yeah, those should be fine. Although typically you'd refer to them as ch 36 and ch 157 (5180MHz and 5785 MHz, respectively).

That depends on your environment -- in other words, what channels your neighbors are using. The best way to figure out the channels to use is based on a radio frequency scan to look at the amount of traffic/noise on each channel and then you select the ones with the lowest noise. But as long as they are non-overlapping (such as the ones you've chosen), the roaming should be fine.

The other thing to adjust is the power levels to ensure that you minimize the amount of overlap (so you're actually reducing power levels). Here's a video that I think does a good job of explaining how to tune your APs (it references Unifi, but the concepts hold true for all wifi APs, as long as the relevant controls are exposed to the user)