Creating a bridged WiFi AP (hotspot) in Centos 8 (or Fedora)
I am trying to create a bridged WiFi hotspot on a Centos 8 system, using NetworkManager. The machine is Dell EPC3000, with two built-it GigE's and ath10k wireless adapter, plus an LTE WWAN.
Creating a NATted hotspot works nicely:
nmcli con add type wifi ifname wlp4s0 con-name wlp4s0 autoconnect yes ssid test
nmcli con modify wlp4s0 802-11-wireless.mode ap 802-11-wireless.band bg ipv4.method shared
nmcli con modify wlp4s0ap wifi-sec.key-mgmt wpa-psk
nmcli con modify wlp4s0ap wifi-sec.psk "password"
nmcli con up wlp4s0ap
This assigns a private IP to the wlp4s0 interface, invokes dnsmasq for dhcp and creates proper iptables configuration for the hotspot.
Now my idea is to do away with NAT and bridge the wifi interface to the secondary GigE, serving wifi clients from that segment with its remote DHCP and other services.
Creating a bridge and enslaving wlp4s0 and the secondary GigE works ok, while the AP remains up & beaconing (using nmcli all the way)
# bridge link
4: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
5: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
When the wlp4s0ap connection is enslaved to br0, it predictably loses its IPv4 settings. The br0 bridge works, as if I enable DHCP on it, it gets IPv4/v6 from the bridged GigE segment.
Now one might think that the bridge configuration would not affect (the dbus-controlled) wpa_supplicant which maintains the access point. However, whenever the wlp4s0 interface is bridged, wpa_supplicant consistently halts WPA authentication half-way when completing EAPOL handshake:
hostapd_logger: STA 84:c7:ea:39:9b:28 - start authentication
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state INITIALIZE
wpa_driver_nl80211_set_key: ifindex=5 (wlp4s0) alg=0 addr=0x55d8a39e0bb0 key_idx=0 set_tx=1 seq_len=0 key_len=0
addr=84:c7:ea:39:9b:28
nl80211: Set STA flags - ifname=wlp4s0 addr=84:c7:ea:39:9b:28 total_flags=0x66 flags_or=0x0 flags_and=0xfffffffe authorized=0
hostapd_logger: STA 84:c7:ea:39:9b:28 - unauthorizing port
WPA: 84:c7:ea:39:9b:28 WPA_PTK_GROUP entering state IDLE
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state AUTHENTICATION
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state AUTHENTICATION2
WPA: Assign ANonce - hexdump(len=32): 6c 11 09 50 95 fc 7d 80 80 a0 a9 a7 be eb 23 d3 ec 6e f4 ef 42 87 ca 45 5e 55 80 5b 54 c0 38 7e
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state INITPSK
Searching a PSK for 84:c7:ea:39:9b:28 prev_psk=(nil)
Searching a PSK for 84:c7:ea:39:9b:28 prev_psk=(nil)
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state PTKSTART
hostapd_logger: STA 84:c7:ea:39:9b:28 - sending 1/4 msg of 4-Way Handshake
WPA: Send EAPOL(version=2 secure=0 mic=0 ack=1 install=0 pairwise=1 kde_len=0 keyidx=0 encr=0)
WPA: Replay Counter - hexdump(len=8): 00 00 00 00 00 00 00 01
WPA: Use EAPOL-Key timeout of 100 ms (retry counter 1)
wlp4s0: hostapd_new_assoc_sta: reschedule ap_handle_timer timeout for 84:c7:ea:39:9b:28 (300 seconds - ap_max_inactivity)
wlp4s0: Event EAPOL_TX_STATUS (37) received
hostapd_logger: STA 84:c7:ea:39:9b:28 - EAPOL-Key timeout
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state PTKSTART
hostapd_logger: STA 84:c7:ea:39:9b:28 - sending 1/4 msg of 4-Way Handshake
WPA: Send EAPOL(version=2 secure=0 mic=0 ack=1 install=0 pairwise=1 kde_len=0 keyidx=0 encr=0)
WPA: Replay Counter - hexdump(len=8): 00 00 00 00 00 00 00 02
WPA: Use EAPOL-Key timeout of 1000 ms (retry counter 2)
wlp4s0: Event EAPOL_TX_STATUS (37) received
hostapd_logger: STA 84:c7:ea:39:9b:28 - EAPOL-Key timeout
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state PTKSTART
hostapd_logger: STA 84:c7:ea:39:9b:28 - sending 1/4 msg of 4-Way Handshake
WPA: Send EAPOL(version=2 secure=0 mic=0 ack=1 install=0 pairwise=1 kde_len=0 keyidx=0 encr=0)
WPA: Replay Counter - hexdump(len=8): 00 00 00 00 00 00 00 03
WPA: Use EAPOL-Key timeout of 1000 ms (retry counter 3)
wlp4s0: Event EAPOL_TX_STATUS (37) received
hostapd_logger: STA 84:c7:ea:39:9b:28 - EAPOL-Key timeout
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state PTKSTART
hostapd_logger: STA 84:c7:ea:39:9b:28 - sending 1/4 msg of 4-Way Handshake
WPA: Send EAPOL(version=2 secure=0 mic=0 ack=1 install=0 pairwise=1 kde_len=0 keyidx=0 encr=0)
WPA: Replay Counter - hexdump(len=8): 00 00 00 00 00 00 00 04
WPA: Use EAPOL-Key timeout of 1000 ms (retry counter 4)
wlp4s0: Event EAPOL_TX_STATUS (37) received
hostapd_logger: STA 84:c7:ea:39:9b:28 - EAPOL-Key timeout
WPA: 84:c7:ea:39:9b:28 WPA_PTK entering state PTKSTART
hostapd_logger: STA 84:c7:ea:39:9b:28 - PTKSTART: Retry limit 4 reached
Knowing that this kind of bridging is the way most Linux-based access points do it, I wonder what Centos 8 does differently to break the wpa_supplicant. I also compiled the newest wpa_supplicant from w1.fi git, but it behaved the same way, working perfectly with NAT but breaking with bridge.
I also fiddled with /sys/class/net/br0/bridge/group_fwd_mask to ensure that no wifi control packets are dropped, no effect.
Tried also generic (compiled) hostapd package outside NetworkManager (used e.g. by DD-WRT access points), but it also breaks WPA once I enable bridging.
Any suggestions what to try next?
I got the bridged AP working by
- compiling and installing hostapd from source
- unmanaging WiFi interface from NetworkManager (nmcli dev set managed no)
- creating a bridge interface with NetworkManager and adding the 2nd Ethernet as a slave
- disabling system-provided wpa_supplicant
- adding "bridge=br0" into hostapd.conf starting hostapd
Now I think this should be possible with NetworkManager and standard wpa_supplicant too, but this solution works for now.
NetworkManager can't create access points that are part of a bridge, see https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/83. This is not unique to Centos. "the way most Linux-based access points do it" is to use hostapd.
NetworkManager / nmcli CAN create access points that are part of a bridge. WPA supplicant seemed to have a problem figuring out the type of interface after bridging, however that was resolved by adding the bridge interface to the command line arguments of wpa_suppliant in /etc/sysconfig/wpa_supplicant (CentOS 8.2)
INTERFACES="-i wlp2s0 -b br0"
Bridging ethernet to wifi interface using nmcli https://unix.stackexchange.com/questions/620169/disable-wifi-security-in-network-manger