ruvnet/RuView · error
veil: genl_ctrl_resolve(nl80211) failed: %d\n
Error message
veil: genl_ctrl_resolve(nl80211) failed: %d\n
What it means
`genl_ctrl_resolve` queries the generic netlink controller for the numeric family id of "nl80211". A negative return (printed as `%d`) means the family is not registered: almost always no cfg80211-based wifi driver is loaded, or the kernel lacks nl80211. Without the family id the daemon can neither listen for MLME events nor send commands, so bring-up aborts.
Source
Thrown at firmware/privshield/openwrt/veil_shieldd.c:80
static void on_signal(int sig) { (void)sig; g_ctx.running = 0; }
/* ---------------------------------------------------------------------- */
/* nl80211 bring-up — all REAL libnl-genl-3 API names. */
/* ---------------------------------------------------------------------- */
static int veil_nl_connect(struct veil_ctx *c) {
c->sock = nl_socket_alloc();
if (!c->sock) {
fprintf(stderr, "veil: nl_socket_alloc failed\n");
return -ENOMEM;
}
if (genl_connect(c->sock)) {
fprintf(stderr, "veil: genl_connect failed\n");
return -EIO;
}
c->family = genl_ctrl_resolve(c->sock, "nl80211");
if (c->family < 0) {
fprintf(stderr, "veil: genl_ctrl_resolve(nl80211) failed: %d\n",
c->family);
return c->family;
}
/* Observe MLME events (auth/assoc, and — where the driver forwards them —
* action-frame notifications). Real multicast group name is "mlme". */
int grp = genl_ctrl_resolve_grp(c->sock, "nl80211", "mlme");
if (grp >= 0) {
(void)nl_socket_add_membership(c->sock, grp);
}
return 0;
}
/* ---------------------------------------------------------------------- */
/* CONTROL 1 (FEASIBLE): TX antenna-map perturbation. */
/* Rotating the allowed TX antenna bitmap changes the static spatial */
/* mapping the PHY uses, coarsely perturbing the CSI a sensor observes. */
/* This is a genuinely userspace-reachable, compliant knob. */
/* NL80211_CMD_SET_WIPHY + NL80211_ATTR_WIPHY_ANTENNA_TX / _RX */View on GitHub (pinned to 4685618388)
Solutions
- Load/enable the wifi driver and verify: `iw dev` should list an interface and `genl-ctrl-list | grep nl80211` should resolve.
- In a VM, pass through a USB dongle backed by a cfg80211 driver, or run directly on the router.
- For custom kernels, enable CONFIG_CFG80211, CONFIG_NL80211, and the radio's mac80211/mt76/ath driver, then rebuild.
Example fix
# before veil_shieldd -i 2 # veil: genl_ctrl_resolve(nl80211) failed: -24 # after opkg install kmod-mt76-core kmod-mt76-usb # driver for the actual radio iw dev && veil_shieldd -i 2
Defensive patterns
Strategy: validation
Validate before calling
#!/bin/sh
# pre-flight: nl80211 family must be registered
iw list >/dev/null 2>&1 || { echo "no cfg80211/nl80211 driver loaded"; exit 1; }
IFIDX=$(cat /sys/class/net/wlan0/ifindex)
exec veil_shieldd -i "$IFIDX" Try / catch
if (g_ctx.family < 0) {
/* nl80211 not registered: load the radio driver or fix the kernel */
fprintf(stderr, "veil: load a cfg80211 driver (kmod-mt76/ath) before starting\n");
return g_ctx.family;
} Prevention
- Gate the init script on `iw dev` / `genl-ctrl-list | grep nl80211` succeeding.
- Keep kmod packages matched to the installed kernel after sysupgrades.
- Don't expect the daemon to work in VMs/containers without a real passed-through radio.
When it happens
Trigger: Running on a host with no wifi driver loaded (`lsmod | grep cfg80211` empty); radio failed to probe at boot (wrong DTS/board data); VM or container without wifi passthrough; custom kernel missing CONFIG_CFG80211/CONFIG_NL80211.
Common situations: Developing/testing the daemon on a laptop or VM with no wireless card; driver crash unloading cfg80211; firmware packages (mt76-*) missing or kernel-mismatched on the router.
Related errors
- veil: genl_ctrl_resolve(nl80211) failed: %d
- ${path}: ${res.status} ${res.statusText}
- brain corpus exceeds 1 MiB
- ENOMEM
- EIO
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/a0a68c3c74ccce7c.
Report an issue: GitHub.