AES-256 ciphers (GCMP-256 / CCMP-256) won't form a mesh link on MM8108

Short version

On an 802.11s mesh, 128-bit ciphers work fine. 256-bit ciphers never form a link.
Same hardware, same firmware, same passphrase — the only thing I change is the cipher.

Setting Cipher used Mesh link?
encryption='sae' CCMP-128 Works
encryption='sae+gcmp' GCMP-128 Works
encryption='sae+gcmp256' GCMP-256 Never links
encryption='sae+ccmp256' CCMP-256 Never links

Both 128-bit options work and both 256-bit options fail, so it looks like the problem is
the 256-bit key length itself, not GCM vs CCM.

The chip says it supports these. iw phy0 info lists CCMP-256 and GCMP-256 alongside the
128-bit ones.

Setup

  • Raspberry Pi 4, OpenWrt 23.05.5
  • MM8108 (B2), SDIO. Driver log line at boot:
    Loaded firmware from morse/mm8108b2-rl.bin
    Morse Micro Dot11ah driver registration. Version 0-rel_1_16_4_2025_Sep_18
  • wpa_supplicant_s1g 1.16.4-2, morse-feed pinned at 263b4c4 (Aug 2025)
  • Two radios, 802.11ah 8 MHz, 802.11s mesh with batman-adv on top
  • Signal −7 to −28 dBm, so this isn’t a weak-signal problem

First problem: the 256-bit setting is silently ignored

Before I could even test this, I found that setting a 256-bit cipher does nothing at all.

/lib/netifd/morse/morse_overrides.sh (around line 1055) only recognises two exact values:

[ "$wpa_cipher" = GCMP ] && { ...pairwise=GCMP... }
[ "$wpa_cipher" = CCMP ] && ...pairwise=CCMP...

GCMP-256 and CCMP-256 match neither, so no cipher line gets written and wpa_supplicant
quietly falls back to CCMP-128. No warning, no error — it just looks like nothing happened.

I think that’s a bug by itself. Even if 256-bit isn’t supported, it shouldn’t silently
downgrade.

I patched that locally to pass the value through, which is how I got to the real issue.

Second problem: with the cipher applied, the link never forms

$ wpa_cli_s1g -i wlan0 status
pairwise_cipher=GCMP-256
group_cipher=GCMP-256
wpa_state=COMPLETED          <- looks fine

$ iw dev wlan0 station dump | grep 'mesh plink'
	mesh plink:	HOLDING      <- never reaches ESTAB

$ batctl n
(no neighbours)

Looking at the keys actually loaded into the driver:

idx1  00-0f-ac:9  32B     <- the 32-byte group key installs fine
                          <- but no idx0 entry: the per-link key is never created

So the 256-bit group key works. The per-link key never gets made, because the two
radios never finish their handshake.

With a 128-bit cipher you instead get three keys (including the per-link one) and
mesh plink: ESTAB within about 70 seconds.

What it looks like from outside

Stations show up in the list and then vanish, over and over. That’s not partial success —
the radio hears its neighbour’s beacons and creates an entry, tries to peer, fails, deletes
the entry, then rediscovers it on the next beacon and repeats.

Throughout all of it: no per-link key, no batman neighbour, no traffic.

Where it actually fails

My first look at the logs was misleading. I saw SAE: Confirm mismatch and lots of
MESH-SAE-AUTH-FAILURE and assumed the password exchange was failing. It isn’t —
MESH-SAE-AUTH-FAILURE is just a 10-second timeout firing, and the short timeout was
causing retries to trip over each other.

I rebuilt with a longer timeout (60s instead of 10s, 10 retries instead of 3) and ran it
for 8 minutes. Much clearer picture:

Log line Count
SAE completed successfully (added PMKSA cache entry) 424
SAE: Confirm mismatch 0
MESH-SAE-AUTH-FAILURE 1
Mesh RSN: invalid peer nonce 60
Link established 0

The password exchange (SAE) is completely fine — it succeeds 424 times. What fails is
the step after it: the peering handshake that exchanges keys. The peer keeps rejecting it
with “invalid peer nonce” and then closes the connection:

MPM: Received PLINK action 3        <- peer sends a Close
MPM: close reason=52
MPM: peer_lid mismatch: 0x0 != 0xccf7
MPM set <peer> from OPN_SNT into HOLDING

Also worth noting: the longer timeout didn’t help at all, so this isn’t a speed problem.

Things I checked in the source

From GitHub - MorseMicro/hostap · GitHub , in case any of these are relevant:

  • The peering element carries the group key, and its size changes with the cipher —
    16 bytes for 128-bit, 32 bytes for 256-bit (mesh_rsn.c:570-574 and :787-794). That’s
    the only part of the handshake whose size depends on the cipher, and it’s the same
    element whose nonce check is failing.
  • SAE-EXT-KEY can’t be used on a mesh. This is the standard way to get longer keys.
    It’s compiled in and in the shipped binary, but mesh.c only checks for plain
    WPA_KEY_MGMT_SAE (bit 10), while SAE_EXT_KEY is bit 26 — so choosing it just turns
    mesh security off entirely.
  • Heads-up for anyone else trying this: using a stronger SAE group (sae_groups=20,
    P-384) does not give you longer keys on a mesh. Key length depends on the AKM, not the
    group. I wasted time on this.
  • Minor: the peering element always claims CCMP as the cipher regardless of what’s
    configured (mesh_rsn.c:592). Nothing reads that field, so it’s harmless today, but it’s
    wrong on the wire.

I tried a lot of variations

All of these fail the same way:

  1. Changing the cipher on a running mesh
  2. Restarting wifi on both radios at once
  3. Using sae_groups=20
  4. Cold-rebooting both radios straight into the 256-bit setting
  5. Using CCMP-256 instead of GCMP-256
  6. Rebuilding with much longer timeouts and retry counts

About newer releases

I’m on 1.16.4 and I know 1.17.8, 1.17.9, mm8108-2.0.0 and mm6108-2.0.1 have since
come out. I checked the mesh source at the mm8108-2.0.0 tag and it’s unchanged in every
place I looked — same hardcoded CCMP, same SAE_PMK_LEN, same timeouts, same SAE-EXT-KEY
lockout, still no 256-bit handling.

But I haven’t tested 2.0.0 on hardware yet. Since the group key installs fine and only the
per-link key fails, a driver or firmware fix would be in exactly the part I can’t inspect —
so if 2.0.0 already fixes this, please say so and I’ll go test it.

Questions

  1. Is GCMP-256 / CCMP-256 supposed to work on an 802.11s mesh with the MM8108? If not,
    I’d rather know now and stop chasing it.
  2. Can the silent downgrade in morse_overrides.sh be fixed? Setting a 256-bit cipher and
    silently getting CCMP-128 is an easy trap to fall into.
  3. Any chance of enabling SAE-EXT-KEY for mesh mode? That’s the proper route to 256-bit
    mesh keys.
  4. Does the firmware handle a 32-byte per-link key at all? I could never get far enough to
    find out.
  5. Is there anything in the peering element handling that assumes a 16-byte group key?

Happy to run more tests, try patches, or send full debug logs.