ruvnet/RuView · error
ENOMEM
ENOMEM
Error message
veil: nl_socket_alloc failed\n
What it means
veil_shieldd is the OpenWrt nl80211 privacy daemon; `veil_nl_connect` begins by allocating a libnl socket handle with `nl_socket_alloc()`. A NULL return is mapped to `-ENOMEM`: the C heap is exhausted or the process hit a memory rlimit before the netlink channel even opens, so the daemon aborts bring-up at its first step.
Source
Thrown at firmware/privshield/openwrt/veil_shieldd.c:71
struct nl_sock *sock; /* generic-netlink socket to nl80211 */
int family; /* resolved "nl80211" genl family id */
int ifindex;/* target AP interface (e.g. phy0-ap0) */
uint64_t key; /* shared session key for the keyed rotation */
size_t passes; /* Givens passes */
volatile sig_atomic_t running;
};
static struct veil_ctx g_ctx;
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);
}View on GitHub (pinned to 4685618388)
Solutions
- Free memory or raise limits: stop unneeded services, raise the cgroup/`ulimit -v` cap, add zram/swap, then restart the daemon.
- Check `dmesg` for the OOM killer selecting veil_shieldd; add memory headroom or respawn throttling under procd.
- If it reproduces with ample free memory, verify runtime libnl matches the SDK: `ldd /usr/sbin/veil_shieldd | grep nl` and compare package versions.
Example fix
# before veil_shieldd -i 2 # veil: nl_socket_alloc failed # after /etc/init.d/uhttpd stop # free RAM on a 32MB target opkg install zram-swap; /etc/init.d/veil_shieldd restart
Defensive patterns
Strategy: validation
Validate before calling
/* headroom check before daemon start */
#include <sys/resource.h>
static int heap_headroom_ok(void) {
struct rlimit rl;
if (getrlimit(RLIMIT_AS, &rl) == 0 && rl.rlim_cur != RLIM_INFINITY
&& rl.rlim_cur < (32ull << 20)) return 0; /* < 32MB cap will likely fail */
return 1;
} Try / catch
if (veil_nl_connect(&g_ctx) != 0) {
fprintf(stderr, "veil: nl80211 bring-up failed; freeing memory and retrying once\n");
/* procd respawn with threshold; do not busy-loop */
return 1;
} Prevention
- Run veil_shieldd under procd with respawn thresholds so OOM kills are bounded.
- Install zram/swap on memory-constrained targets.
- Keep runtime libnl3 and libnl-genl3 versions identical to the SDK the binary was built with.
When it happens
Trigger: Embedded router with 32-64 MB RAM under boot-time memory pressure; `ulimit -v` / cgroup memory caps on the daemon; a leaky supervisor restart loop; ABI-mismatched libnl3/libnl-genl3 returning garbage.
Common situations: Low-RAM OpenWrt targets running many services; OOM pressure from the wifi stack itself; chroot/proot environments intercepting allocation; SDK-built binary deployed against different libnl than linked.
Related errors
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/0c99129a223b0988.
Report an issue: GitHub.