# FreeBSD bwn driver fixes for Broadcom BCM43224 (Apple MacBook Air A1370) A complete, self-contained set of fixes that make the FreeBSD `bwn(4)` driver work on the Apple MacBook Air A1370's BCM43224 (PCI `0x14e4:0x4353`, subvendor `0x106b:0x00d1`) 802.11a/b/g/n chip. The driver has been tested through multiple `kldunload`/`kldload` cycles and reboots on the target hardware with no panic. ## Build & install (clean FreeBSD 15.1) You need the FreeBSD 15.1 **source tree** at `/usr/src` (or pass an alternate `SRC_ROOT` to the scripts). Then, as root: ```sh cd bwn-a1370 sudo ./apply.sh # patch /usr/src (or: sudo ./apply.sh /path/to/src) sudo ./build.sh # build + install if_bwn.ko, bhndb_pci.ko, bwn_v4_n.ko reboot ``` After reboot, bring up the interface: ```sh ifconfig wlan create wlandev bwn0 [wap] # or, to join a WPA network, create the wlan and run wpa_supplicant as usual ``` `build.sh` installs everything for the **next boot**; it does not touch the running kernel, so an active session (e.g. SSH over a fallback `rtwn0/wlan0` interface) is never disrupted. ### What the scripts do - `apply.sh` — idempotently applies the 4 source patches to `/usr/src` (`patches/patch-*.c` and `patches/patch-Makefile`). Safe to re-run. - `build.sh` — builds `if_bwn.ko` (`sys/modules/bwn`), `bhndb_pci.ko` (`sys/modules/bhnd/bhndb_pci`), and `bwn_v4_n.ko` (from `src/firmware/`); installs them to `/boot/modules` and `/boot/kernel`; and appends `bwn_v4_n_load="YES"` to `/boot/loader.conf` if missing (Fix 5). ### Manual build (equivalent to build.sh) ```sh SRC=/usr/src # 1. driver make -C $SRC/sys/modules/bwn SRCTOP=$SRC SYSDIR=$SRC/sys install -m 444 $SRC/sys/modules/bwn/if_bwn.ko /boot/modules/ # 2. PCIe bridge (NO_MSI quirk) make -C $SRC/sys/modules/bhnd/bhndb_pci SRCTOP=$SRC SYSDIR=$SRC/sys install -m 444 $SRC/sys/modules/bhnd/bhndb_pci/bhndb_pci.ko /boot/kernel/ # 3. firmware make -C src/firmware SRCTOP=$SRC SYSDIR=$SRC/sys install -m 444 src/firmware/bwn_v4_n.ko /boot/modules/ # 4. loader.conf (Fix 5) echo 'bwn_v4_n_load="YES"' >> /boot/loader.conf ``` ## Directory layout ``` bwn-a1370/ README.md This file (rebuild guide) RESEARCH.md Root-cause investigation log (Fixes 5-8) apply.sh Apply the 4 source patches to /usr/src (idempotent) build.sh Build + install all 3 modules and add the loader.conf entry loader.conf.bwn Snippet for /boot/loader.conf (Fix 5: load firmware at boot) patches/ patch-if_bwn.c Driver fixes (Fixes 1-4, 6-8) patch-Makefile GPL PHY build wiring (Fix 1) patch-bhndb_pci.c NO_MSI quirk for BCM43224 (Fix 7) patch-bhndb_pcivar.h NO_MSI quirk definition (Fix 7) combined.patch All of the above in one file (alternative to apply.sh) src/firmware/ Broadcom v4 firmware module (bwn_v4_n.ko) sources + Makefile rc.conf.backups/ Backups of loader.conf/rc.conf made by the scripts ``` ## What was broken (summary) On a stock FreeBSD 15.1 system this chip (an N-PHY rev-23 core behind a BCMA/bhnd bus, attached via the `bhndb_pci` PCIe-G1 bridge) failed in several ways: 1. The GPL N-PHY code is not compiled in (build wiring). 2. A NULL ring pointer can be dereferenced on a partial attach. 3. Multicast updates are not wired to `ic->ic_update_mcast`. 4. Firmware is not found at attach (loader vs kld_list ordering). 5. **MSI interrupts are never delivered** on this host (NVIDIA MCP89 bridge), so TX completions never run -> "device timeout" and the NIC never passes traffic. 6. Detaching while a TX frame is pending double-frees an `ieee80211_node` (kernel panic). 7. Reclaiming the **RX** ring at device-stop DMAs received frames into freed kernel memory -> heap corruption / TCP panic. | # | Area | Problem | Fix | |---|------|---------|-----| | 1 | build | GPL N-PHY code not compiled in | `BWN_GPL_PHY` via `opt_bwn.h`; add 7 GPL PHY files to `SRCS` in `modules/bwn/Makefile` | | 2 | `bwn_dma_ringfree` | NULL ring deref on partial attach | NULL-guard `if (dr == NULL \|\| *dr == NULL) return;` | | 3 | `bwn_update_mcast` | mcast not updated | wire to `ic->ic_update_mcast` | | 4 | `build.sh` | reload clobbered live iface | unload/rebuild/reinstall/reload `if_bwn` only | | 5 | `/boot/loader.conf` | firmware not found at attach | `bwn_v4_n_load="YES"` loads firmware at loader stage | | 6 | `bwn_dma_stop` | detach double-frees node (vmcore.4) | reclaim pending TX frames (drop node refs) at device-stop | | 7 | `if_bwn` + `bhndb_pci` | node ref ownership + MSI never delivered (vmcore.5 / "device timeout") | driver takes its own `ieee80211_ref_node()`; remove `dr_usedslot` early-return; `BHNDB_PCI_QUIRK_NO_MSI` for BCM43224 forces legacy INTx | | 8 | `bwn_dma_stop` | RX-ring reclaim -> heap corruption (vmcore.6) | restrict reclaim to TX rings only (new `bwn_dma_reclaim_tx()`) | ## Files modified in /usr/src - `sys/dev/bwn/if_bwn.c` - `sys/modules/bwn/Makefile` - `sys/dev/bhnd/bhndb/bhndb_pci.c` - `sys/dev/bhnd/bhndb/bhndb_pcivar.h` (Plus the prebuilt `bwn_v4_n.ko` firmware, reproducible from `src/firmware/`.) See `RESEARCH.md` for the full root-cause analysis behind each fix. ## Credits Created by Luxferre in 2026, released into the public domain with no warranties.