wifip2pd leaks file descriptors during repeated Wi-Fi Aware NDP cycles → EMFILE → Wi-Fi Aware permanently broken
Summary
Under repeated Wi-Fi Aware (NAN) datapath connect/teardown cycles, wifip2pd leaks file descriptors until it hits the per-process limit (EMFILE, "Too many open files"). After that, wifip2pd can no longer create the socket needed to configure the nan0 interface, so updating the nan0 IPv6 link-local address fails with Apple80211Error Bad file descriptor. From the app's side, the NDP datapath is established but the NetworkConnection never gets a local IPv6 address and stays stuck in .preparing. The condition does not self-heal and is not cleared by restarting the app — only a reboot (or wifip2pd restart) recovers Wi-Fi Aware.
Configuration
- iPhone 16 Pro Max, iOS 26.5
- Network framework (new Swift
NetworkConnection/NetworkBrowserWi-Fi Aware API) - System component:
wifip2pd
Where the problem is
The leak and the failure are entirely inside wifip2pd (the per-process descriptor table fills up). The chain is:
fd leak in wifip2pd → EMFILE ("Too many open files", errno 24)
→ socket() fails
→ cannot set nan0 IPv6 link-local address (Apple80211 ioctl on invalid fd → EBADF)
→ app NWConnection NWPath = satisfied but localEndpoint = nil
→ NetworkConnection stuck in .preparing, times out
Abnormal console logs (the evidence)
The smoking-gun lines from the unified log / Console (process wifip2pd):
wifip2pd <Error> Failed to create socket: Too many open files
wifip2pd <Error> Failed to update nan0 IPv6 address to [fe80::30c1:22ff:fe97:fefb]
(from [fe80::e8a0:9bff:fe25:4d5c]) because <Apple80211Error Bad file descriptor>
wifip2pd <Error> nw_path_shared_necp_fd necp_open failed [24: Too many open files] # errno 24 = EMFILE
wifip2pd(Network) <Error> File descriptor is bad, could not create socket
Counts over one ~11.5-minute failing capture:
wifip2pd"Too many open files": 45 occurrences (a healthy capture has 0).nan0IPv6 address update: 2 success / 13 fail (the 2 successes are before exhaustion; everything after fails with "Bad file descriptor").
Healthy device, for contrast — the IPv6 update succeeds on every NAN MAC rotation, and the app connection then works:
wifip2pd Successfully updated nan0 IPv6 address to [fe80::f4c4:14ff:fe28:784a]
# → app NWPath: status=satisfied, local=fe80::f4c4:14ff:fe28:784a%nan0 → NetworkConnection .ready
Two facts that localize the bug:
- The leak is in
wifip2pd, not the app.wifip2pdis one persistent daemon (constant pid) whose fd count only grows; the client app was restarted multiple times during the test and that did not release the descriptors. All "Too many open files" lines are emitted bywifip2pd. - The NDP datapath itself still succeeds — only socket/interface-address configuration fails:
kernel nan0: handleDataPathEstablished: NAN-DP Data path ESTABLISHED ... encrypt 1, EstDPs 1 wifip2pd #### Data Confirmed With Peer: ... port: 9004
Application-layer symptom (developer-facing)
The same client code works before exhaustion and fails after:
- Before:
NetworkConnection<UDP>reaches.ready;NWPath.localEndpoint = fe80::…%nan0. - After:
NetworkConnection<UDP>stays.preparing; everyonPathUpdatereportsstatus=satisfied, interfaces=["nan0"], local=nil; it times out and retries forever.
The decisive developer-visible signal is NWPath.status == .satisfied together with localEndpoint == nil on nan0. Correlating timestamps confirms the contradiction: the console shows Data Confirmed With Peer ... port 9004 ~9–10 s before the app's NetworkConnection gives up, while the matching nan0 IPv6 update fails with "Bad file descriptor". The datapath is up at L2, but the connection is unusable because no local address was ever assigned.
Steps to Reproduce
- Pair an iPhone with a Wi-Fi Aware peer that publishes a datapath service (
_media-sync._udp, paired device,NCS-SK-CCM-128). - Repeatedly establish and tear down the NDP datapath. In our case the peer device repeatedly powers off/on; each cycle forces a fresh browse + re-pair + NDP establish (the peer's NAN MAC is randomized each boot).
- Loop this;
wifip2pdis never restarted, so the leak accumulates (failure appeared by ~the 9th iteration).
Expected vs Actual
- Expected:
wifip2pdreleases the descriptors of each completed/torn-down browse/subscribe/datapath session; fd count stays bounded;nan0IPv6 updates keep succeeding;NetworkConnectionreaches.ready. - Actual:
wifip2pdfd count grows untilEMFILE;nan0IPv6 update then fails permanently;NetworkConnectionis stuck.preparingfor the rest of thewifip2pdprocess lifetime.
Impact
Any app using Wi-Fi Aware NDP datapaths under frequent connect/teardown eventually loses all Wi-Fi Aware connectivity. The failure is sticky for the wifip2pd lifetime and is invisible to / unrecoverable by the client app.
Workaround
Reboot the device (resets wifip2pd). The client can only slow the leak (fewer reconnects, prompt release of NetworkConnection), not prevent it, since the descriptors leak inside wifip2pd.
To confirm / fix
A sysdiagnose captured during the reproduction should show wifip2pd's open-fd count growing monotonically per connect/teardown cycle (which descriptor type leaks per browse/subscribe/datapath). Repro signature to grep in the logs: wifip2pd emitting Failed to create socket: Too many open files, necp_open failed [24: Too many open files], and Failed to update nan0 IPv6 address ... Apple80211Error Bad file descriptor.