WLAN on NextBSD — the Apple stack, and why we use wpa_supplicant RESEARCH

What macOS actually uses for WLAN (it is not wpa_supplicant), what Apple published and what it kept closed, and how Apple's stack compares function-for-function against wpa_supplicant and iwd. Background reading for the NextBSD WLAN plan.

This is the research, not the plan. It establishes why NextBSD cannot port Apple's wifid (closed, and welded to a kernel framework that does not exist here), why wpa_supplicant is the only viable protocol engine (BSD-licensed, and the only one that speaks net80211), and why iwd is not (nl80211-welded, LGPL). Those conclusions hold.

For what to actually build — the missing wlan_xauth, the VAP-creation gap, the DHCP-before-4-way-handshake race, and the wifid design — see the NextBSD WLAN plan.

TL;DR

1. Apple's WLAN stack

Multiple components, layered. From hardware up:

ComponentRoleSource
IO80211Family.kext + per-vendor drivers (AirPortBrcmNIC, AppleBCMWLANCore, etc.) Kernel WLAN driver framework. Hardware-specific drivers attach here. Provides the IEEE 802.11 MAC/PHY layer to userspace. Closed
wifid (binary at /usr/libexec/wifid) The main WLAN management daemon. Runs as a launchd job (com.apple.wifid.plist). Owns: AP scanning, BSS selection, association, WPA2/WPA3 4-way handshake, key management, autojoin policy, profile management, fast-roam (802.11r/k/v) coordination. Closed
eapolclient (binary at /usr/libexec/eapolclient) Per-iface 802.1X authentication daemon. wifid spawns one per WLAN iface that needs EAP. Implements EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, EAP-AKA, LEAP. Talks to wifid via Mach IPC for key delivery. Openapple-oss-distributions/eap8021x
EAPOLController.bundle configd plugin coordinating EAP state across services. Acts as the dispatcher between configd's dynamic store and per-iface eapolclient processes. Partial — interfaces in eap8021x repo, controller plugin closed
Apple80211.framework Private 802.11 API the system uses internally. Wraps Mach IPC to wifid. Header in /System/Library/PrivateFrameworks/Apple80211.framework/Headers/Apple80211API.h. Closed
CoreWLAN.framework Public API for third-party apps. Wraps Apple80211. CWInterface, CWNetwork, CWWiFiClient classes. The airport(8) CLI tool is built on this. Headers public, impl closed
AirPort.framework Older WLAN API; mostly superseded by CoreWLAN. Still present for compatibility. Closed
networksetup(8) / airport(8) CLIs User-facing tools for WLAN config. networksetup for general network, airport for WLAN-specific (scan, info, sniff). Both are CoreWLAN clients. Closed
SecKeychain integration WLAN passwords stored in the user's keychain via Security.framework. Per-network credentials, per-user. Security.framework partial open

Net: only the EAP authentication piece is published. The 802.11 association layer, scanning, key management, profile storage — all closed.

1.1 The architecture diagram

+----------------------+ +-----------------------+ | WLAN prefs UI | | Third-party apps | | (System Settings) | | (CWInterface, etc.) | +-----------+----------+ +-----------+-----------+ | | v v +-----------+--------------------------+-----------+ | CoreWLAN.framework (public API) | +-----------+--------------------------+-----------+ | v Mach IPC +-----------+----------+ | Apple80211.framework | +-----------+----------+ | v Mach IPC (com.apple.wifi.client) +-----------+----------+ +--------------------+ | wifid | | eapolclient (per | | (.plist as launchd |<---->| wlan iface) | | job; closed src) | | (eap8021x repo, | +-----------+----------+ | open src) | | +---------+----------+ v | +-----------+----------+ | | IO80211 user client | | | (IOKit Mach port) | | +-----------+----------+ | | | v v +-----------+----------+ +---------+----------+ | IO80211Family.kext | | Keys via Mach back | | + vendor drivers |<-----| to wifid for kernel| | (closed src) | | install | +----------------------+ +--------------------+

2. Open source status — what's actually published

RepoWhat's in itUseful for FreeBSD?
apple-oss-distributions/eap8021x The eapolclient binary source, libeap.a (EAP method library), the EAP-TLS/PEAP/TTLS/FAST/SIM/AKA implementations, EAPOL state machine. Yes, partially. If we ever need EAP methods wpa_supplicant lacks (rare — wpa_supplicant covers all the standard ones). Would need glue to wpa_supplicant or its own supplicant layer.
(no repo) — wifid The main WLAN management daemon n/a — closed source
(no repo) — Apple80211.framework Private 802.11 API n/a — closed source. But the Apple80211API.h header is technically published (via dump tools); reverse-engineered Mach IPC shape is documented in projects like HelloWifid (HelloSystem's exploratory wifid replacement).
(no repo) — IO80211Family.kext Kernel WLAN driver framework n/a — closed source. FreeBSD has its own (net80211(4)); architecturally different.
apple-oss-distributions/IOKitTools kextd, kextload, kextstat — kext loading infrastructure For kmodloader plan, yes (referenced for design). For WLAN, no.
apple-oss-distributions/Security Security.framework — Keychain Services, code signing, certificate handling Maybe long-term for keychain-equivalent; not for WLAN specifically.

So when people say "Apple uses eapolclient" — that's true for the 802.1X piece, and that piece IS open source. But "Apple's WLAN" as a whole is overwhelmingly closed.

3. macOS WLAN stack vs wpa_supplicant

Function-by-function comparison.

FunctionmacOSwpa_supplicant (FreeBSD/Linux)
WPA2-PSK 4-way handshake wifid (closed) wpa_supplicant (open, BSD)
WPA3-SAE association wifid (closed) wpa_supplicant (open) — full RFC 7664 SAE
OWE (Opportunistic Wireless Encryption) wifid (closed) wpa_supplicant (open) — RFC 8110
Open / WEP (legacy) wifid wpa_supplicant — though WEP is mostly removed/deprecated
EAP-TLS / EAP-PEAP / EAP-TTLS eapolclient (semi-open via eap8021x) wpa_supplicant (built-in)
EAP-FAST eapolclient (open via eap8021x) wpa_supplicant (built-in, less-tested than Apple's)
EAP-SIM / EAP-AKA eapolclient (open via eap8021x) wpa_supplicant (built-in but needs SIM card hardware integration)
AP scanning wifid (closed) wpa_supplicant + cfg80211/net80211 (open)
BSS selection / autojoin wifid (closed; uses Apple's signal-strength + history heuristics) wpa_supplicant (configurable; defaults to first match)
802.11r fast roaming wifid (closed) wpa_supplicant (open)
802.11k / 802.11v (radio resource mgmt) wifid (closed) wpa_supplicant (open, partial)
P2P / Wi-Fi Direct wifid (closed; AirDrop is built on this) wpa_supplicant (open, full P2P stack)
AP mode (host the network) wifid (Internet Sharing) hostapd (separate daemon, open)
Profile / credential storage SecKeychain (per-network, per-user) /etc/wpa_supplicant.conf (system-wide) or per-iface configs
User control CLI networksetup, airport(8) wpa_cli
User control GUI System Settings WLAN pane (CoreWLAN client) NetworkManager-applet, iwd, wpa_gui, etc.
DHCP coordination wifid → IPConfiguration via configd dynamic store wpa_supplicant ASSOCIATED state → DHCP client. (On NextBSD there is no such hook: ipconfigd triggers on link-state alone and fires before the 4-way handshake — see the plan §1.3.)

Conclusion: wpa_supplicant covers everything that matters functionally. Apple's wifid has more sophisticated autojoin heuristics and tighter integration with proprietary features (AirDrop, Continuity), but the protocol coverage is essentially equal.

4. Who does what: wifid responsibilities mapped onto wpa_supplicant vs iwd

The word supplicant is the source of most confusion in this whole area, so pin it down first:

Apple split those two apart (narrow eapolclient + closed wifid for everything else); wpa_supplicant and iwd fuse them into one process. That mismatch is why a one-to-one comparison needs the table below rather than a single sentence.

So what does wifid actually own? Everything except the EAP exchange: scanning, AP selection, the association state machine, the WPA2/WPA3 4-way handshake (often firmware-offloaded via IO80211), key installation, roaming, autojoin policy, profile/keychain storage, and the Apple-proprietary peer-to-peer features. eapolclient is spawned by wifid only for Enterprise networks, runs the EAP method, derives the PMK, and hands it back to wifid over Mach IPC — then it's done.

Here is each wifid responsibility mapped onto the two open-source engines. The reading: iwd is closer to wifid on exactly the rows where wpa_supplicant is weak (policy, profiles, API shape), but loses decisively on the one row that gates a FreeBSD port (driver backend) — and on license.

Apple componentwpa_supplicantiwd
eapolclient (EAP / 802.1X) ✅ built in — full EAP method set ✅ built in — own EAP stack on ell (TLS / PEAP / TTLS / PWD / SIM / AKA, WPA3-Enterprise incl. 192-bit)
wifid: 4-way handshake / SAE / key mgmt ✅ built in ✅ built in — userspace; full WPA3-SAE
wifid: scan / associate driving via driver_bsd.cnet80211 ⚠️ nl80211 / cfg80211 only — no net80211, no FreeBSD path
wifid: autojoin / policy / roaming heuristics ❌ minimal — just a priority field ✅ strong & built in — autoconnect, RSSI ranking, FT/802.11r, 802.11k neighbor reports
wifid: profiles / known-networks / keychain flat wpa_supplicant.conf ✅ partial — first-class KnownNetwork model, auto-managed per-SSID profile files, Agent for credential prompts (but flat files, no keychain)
wifid: AWDL / Continuity / AirDrop — P2P stack exists, no Apple glue — limited P2P, no Apple glue

One more dimension that isn't a wifid sub-feature but matters a lot for "Apple-shape" — the control API style, i.e. how a management layer above it issues commands and reads state:

Dimensionwpa_supplicantiwd
Control API shape Line-oriented text command stream (SCAN, ADD_NETWORK, …) over a UNIX socket D-Bus object modelStation / Device / Network / KnownNetwork / Agent objects with properties, methods, signals
Net conclusion — blueprint vs engine. iwd's KnownNetwork / Agent / Station objects map almost one-to-one onto CoreWLAN's CWNetwork / credential-prompt / CWInterface, and it already contains the autojoin/roaming "brain" that wpa_supplicant lacks — so it is the better design reference for what wifid should expose. But iwd is welded to Linux's nl80211/cfg80211 (no net80211 backend) and is LGPL-2.1 (can't go in base), so it is not shippable here. wpa_supplicant wins the two non-negotiable rows — runs on net80211 today and is BSD-licensed. So the wifid we reconstruct is: wpa_supplicant for the protocol engine (rows 1–3), wifid for the brain (rows 4–5), with iwd's object model as the design reference for the brain's API. iwd contributes ideas; wpa_supplicant contributes code.

6.1 Glossary — what each of these things actually is

TermWhat it is
AWDL
(Apple Wireless Direct Link)
Apple's proprietary peer-to-peer WLAN protocol. Lets two Apple devices talk directly without a shared access point by having the WLAN radio time-slice between the normal infrastructure network and an ad-hoc AWDL channel. It is the transport layer underneath AirDrop, AirPlay peer-to-peer, and Continuity features. Closed and Apple-specific; there is no open-source equivalent (the reverse-engineered OWL / "Open Wireless Link" research project is the only outside implementation).
AirDrop Apple's ad-hoc file-sharing feature. Uses Bluetooth LE to discover nearby devices and negotiate, then brings up an AWDL WLAN link for the actual high-speed transfer. So AirDrop = discovery (BLE + Bonjour/mDNS) + transport (AWDL). Reproducing it needs both the AWDL layer and the Bonjour service-discovery layer (see the mDNSResponder plan).
Continuity The umbrella name for Apple's cross-device handoff features — Handoff, Universal Clipboard, Instant Hotspot, iPhone-as-webcam, etc. Many of them ride on AWDL + BLE + Bonjour, coordinated by higher-level daemons. WLAN-relevant only insofar as several Continuity features depend on AWDL being available.
P2P / Wi-Fi Direct The standard (Wi-Fi Alliance) peer-to-peer WLAN mechanism — the open-standard analog of AWDL. wpa_supplicant ships a full P2P stack; iwd's is limited. Neither speaks AWDL, so neither interoperates with AirDrop without an additional Apple-protocol layer on top.
EAP
(Extensible Authentication Protocol)
The authentication framework used by Enterprise WLAN (802.1X). Not one protocol but a family of methods — EAP-TLS (client certs), PEAP / EAP-TTLS (username+password inside a TLS tunnel), EAP-FAST, EAP-SIM / EAP-AKA (cellular SIM-based). This is the only part Apple open-sourced, as eapolclient in the eap8021x repo.
EAPOL
(EAP over LAN)
The link-layer framing that carries EAP messages (and the 4-way handshake's key frames) between the client and the access point. The "EAPOL state machine" is the logic that sequences those frames.
4-way handshake The WPA/WPA2/WPA3 key-exchange that runs after authentication. Using a shared master key (the PMK — from the WLAN password for Personal, or from EAP for Enterprise), client and AP exchange four messages to derive and install the per-session encryption keys (PTK/GTK). On Apple this is owned by wifid (often firmware-offloaded), not eapolclient.
PMK / PTK / GTK The key hierarchy. PMK (Pairwise Master Key) is the root secret for a session. PTK (Pairwise Transient Key) encrypts unicast traffic for one client. GTK (Group Temporal Key) encrypts broadcast/multicast for everyone on the AP. The 4-way handshake derives PTK/GTK from the PMK.
SAE
(Simultaneous Authentication of Equals)
The handshake that replaces the WPA2-PSK password exchange in WPA3-Personal. Resistant to offline dictionary attacks (you can't crack the password by capturing the handshake). Also called "Dragonfly." Both wpa_supplicant and iwd implement it fully.
OWE
(Opportunistic Wireless Encryption)
"Enhanced Open" — encrypts traffic on open (passwordless) networks via an unauthenticated Diffie-Hellman exchange, so a café network gets encryption without a shared password. RFC 8110.
WPA3-Enterprise 192-bit
(Suite B / CNSA)
The high-security Enterprise tier: AES-256-GCMP encryption, mandatory protected management frames and server-certificate validation, defense/government-grade cipher suites. In wpa_supplicant it's the WPA-EAP-SUITE-B-192 key-mgmt mode.
PMF / 802.11w
(Protected Management Frames)
Cryptographic protection for WLAN management frames (deauth/disassoc), which were historically unprotected and spoofable. Optional under WPA2, mandatory under WPA3.
802.11r (FT) Fast BSS Transition — lets a client roam between access points on the same network without redoing the full authentication+handshake each time, so voice/video calls don't drop. The "roaming" part of autojoin policy.
802.11k / 802.11v Radio Resource Management (k) and BSS Transition Management (v) — the AP gives the client a "neighbor report" of nearby APs and can steer it to a better one, so roaming decisions are informed rather than blind.
net80211 FreeBSD's in-kernel 802.11 stack — the layer WLAN drivers plug into and that userspace supplicants drive. wpa_supplicant talks to it through driver_bsd.c. The FreeBSD analog of Apple's IO80211Family.
nl80211 / cfg80211 Linux's in-kernel 802.11 stack (cfg80211) and the netlink API to it (nl80211). iwd is built exclusively on this — which is precisely why it doesn't run on FreeBSD's net80211 without a major porting effort.
ell
(Embedded Linux Library)
Intel's small utility/crypto library that iwd is built on (instead of OpenSSL + glib). Keeps iwd dependency-light, but is itself Linux-oriented and LGPL-2.1 — another thing that would have to be ported.
KnownNetwork / Agent (iwd) iwd D-Bus objects. KnownNetwork = a remembered network with auto-managed profile storage and autoconnect ranking (the analog of a saved WLAN profile / CoreWLAN configuration). Agent = the interface iwd calls back into when it needs a credential, i.e. the "prompt the user for the password" hook (the analog of Apple's keychain/UI prompt flow).
CoreWLAN
(CWInterface / CWNetwork)
Apple's public Objective-C WLAN API for apps. CWInterface = a WLAN adapter (scan, associate, power); CWNetwork = a discovered network. This is the API surface wifid would replicate so Gershwin apps look like Mac apps.

5. References