I decided to replace my Chateau 5G ax with a hEX PoE that I had lying around. The Chateau served me well at my previous place where there was no reasonably priced cable connection, so 5G on a SIM card was the way to go. But after I moved, I got a great fiber optics connection and the 5G modem became useless. I also built a new rack and the Chateau with all its antennas sticking out is not really a rack species — it had to go. The hEX PoE on the other hand fits nicely into a rack, has PoE outputs which I really needed for powering my wAP ax access points and a PoE smart doorbell, and it just made more sense overall. Not really an upgrade in terms of processing power, but I was not using that to the fullest anyway. I wrote about the Chateau and its Wi-Fi quirks in my Wi-Fi ACL on RouterOS 7 post.
With the Chateau gone, all Wi-Fi would be handled by wAP ax units managed centrally via CAPsMAN. The idea is simple: two SSIDs (main and guest) on both 2.4GHz and 5GHz bands, giving 4 wireless networks per access point. The reality was far from simple and it took me a whole evening to get it working.
The setup #
The hEX PoE (RB960PGS) acts as a router and CAPsMAN controller. It has no
Wi-Fi radios of its own but can manage remote radios via the wifi
package. Two wAP ax units plug into its PoE ports and get both power and
network from a single cable each. I keep the configs version controlled
thanks to my backup routine
which made the troubleshooting much easier.
The CAPsMAN configuration consists of two configs and two provisioning rules:
/interface wifi configuration
add channel.skip-dfs-channels=10min-cac country=Slovakia datapath.bridge=\
bridge1 disabled=no name=cfg1 security.authentication-types=wpa2-psk \
.ft=yes .ft-over-ds=yes .passphrase=SECRET ssid=MyNetwork
add country=Slovakia datapath.bridge=bridge1 .traffic-processing=on-cap \
.vlan-id=10 disabled=no name=cfg2 security.authentication-types=wpa2-psk \
.ft=yes .ft-over-ds=yes .passphrase=SECRET ssid=GuestNetwork
/interface wifi provisioning
add action=create-dynamic-enabled master-configuration=cfg1 \
slave-configurations=cfg2 supported-bands=2ghz-ax
add action=create-dynamic-enabled master-configuration=cfg1 \
slave-configurations=cfg2 supported-bands=5ghz-ax
When a wAP ax connects and its CAP mode discovers the CAPsMAN controller, each of its two radios should be matched by the provisioning rules. For each radio, CAPsMAN creates a master interface with cfg1 (main network) and a slave interface with cfg2 (guest network on VLAN 10). Two radios times two configs equals four networks. That is the theory. In practice, I kept getting only three.
Problem 1: stale internal IDs in provisioning rules #
This was the most sneaky one. When you remove and recreate a configuration in RouterOS, it gets a new internal ID. But any provisioning rules that referenced the old configuration keep pointing to the old ID. You can see this in the output:
/interface wifi provisioning print detail
0 supported-bands=2ghz-ax action=create-dynamic-enabled
master-configuration=cfg1 slave-configurations=*2
1 supported-bands=5ghz-ax action=create-dynamic-enabled
master-configuration=cfg1 slave-configurations=*2
Notice slave-configurations=*2 instead of slave-configurations=cfg2.
The *2 was an internal ID of a configuration that no longer existed.
CAPsMAN happily created the slave interfaces but they had no actual
configuration behind them:
cap-wifi1-virtual1 cap-wifi1 Hostia
The comment on this interface read SSID not set even though it showed the
guest SSID in the configuration column. The fix was to recreate the
provisioning rules:
/interface wifi provisioning remove [find]
/interface wifi provisioning add action=create-dynamic-enabled \
supported-bands=2ghz-ax master-configuration=cfg1 \
slave-configurations=cfg2
/interface wifi provisioning add action=create-dynamic-enabled \
supported-bands=5ghz-ax master-configuration=cfg1 \
slave-configurations=cfg2
After this, the slave configurations showed cfg2 by name in the
provisioning rules instead of a stale *2 reference.
Problem 2: mixed traffic processing modes #
With the provisioning rules fixed, the 2.4GHz slave appeared but showed a concerning message:
operated by CAP F4:1E:57:XX:XX:XX%bridge1, traffic processing on CAPsMAN (no encryption)
The “no encryption” part was alarming. It turned out that cfg1 (main
network) defaulted to traffic-processing=on-cap while cfg2 (guest
network) was explicitly set to traffic-processing=on-capsman. This mixed
mode, where the master interface processes traffic locally on the CAP but
the slave tunnels it back to the controller, caused the encryption status
to show incorrectly.
Setting both to the same mode fixed it:
/interface wifi configuration set cfg2 datapath.traffic-processing=on-cap
The comment then changed to simply:
operated by CAP F4:1E:57:XX:XX:XX%bridge1, traffic processing on CAP
No more “no encryption” message.
Problem 3: DFS blocking the 5GHz slave #
Even after fixing the first two problems, the 5GHz slave (cap-wifi2-virtual1) remained inactive. Looking at the CAPsMAN interface list revealed the issue:
cap-wifi2 MDB DFS channel availability check (10 min)
cap-wifi2-virtual1 DBI
The 5GHz master was stuck in a DFS Channel Availability Check. On the CAP side, the radio was actually running fine on channel 5500, but CAPsMAN thought the DFS check was still ongoing and refused to create the slave virtual interface.
The Chateau had channel.skip-dfs-channels=10min-cac on its local 5GHz
radio, but this setting was not present in cfg1 which is the CAPsMAN
configuration pushed to remote radios. Adding it was the fix:
/interface wifi configuration set cfg1 channel.skip-dfs-channels=10min-cac
After re-provisioning, the DFS check completed in 1 minute instead of getting stuck, and all four interfaces came up:
cap-wifi1 Bezdrotova-siet MDB
cap-wifi1-virtual1 Hostia DB
cap-wifi2 Bezdrotova-siet MDB
cap-wifi2-virtual1 Hostia DB
The wAP ax side #
For completeness, the CAP configuration on each wAP ax is minimal. The CAPsMAN controller handles everything, the access point just needs to know where to find it:
/interface bridge
add admin-mac=04:F4:1C:XX:XX:XX auto-mac=no name=bridgeLocal vlan-filtering=yes
/interface wifi datapath
add bridge=bridgeLocal name=capdp
/interface wifi
set [ find default-name=wifi1 ] configuration.manager=capsman \
configuration.mode=ap datapath=capdp disabled=no
set [ find default-name=wifi2 ] configuration.manager=capsman \
configuration.mode=ap datapath=capdp disabled=no
/interface bridge port
add bridge=bridgeLocal interface=ether1
add bridge=bridgeLocal interface=ether2
/interface bridge vlan
add bridge=bridgeLocal tagged=bridgeLocal,ether1 vlan-ids=10
add bridge=bridgeLocal untagged=ether1,ether2 vlan-ids=1
/interface wifi cap
set discovery-interfaces=bridgeLocal enabled=yes
/ip dhcp-client
add interface=bridgeLocal
The bridge needs VLAN 10 tagged because the guest network uses
traffic-processing=on-cap with vlan-id=10. The CAP processes guest
traffic locally and sends it tagged over the trunk to the controller where
it gets routed to the guest VLAN.
Lessons learned #
Three separate issues combined to create what looked like a single problem of “only 3 out of 4 networks work”. Each fix was necessary but not sufficient on its own:
- When you recreate a CAPsMAN configuration, always recreate the provisioning rules too, otherwise they keep referencing stale internal IDs
- Do not mix
traffic-processingmodes between master and slave configurations on the same radio - If the CAPsMAN controller manages radios on DFS channels, set
channel.skip-dfs-channelsin the CAPsMAN configuration, not just on local interfaces
I have not found any of these documented clearly in one place, so hopefully this saves someone the evening I spent on it. Enjoy!