NextBSD configd — porting plan Filed under: freebsd-launchd-mach (v2) effort PARTIALLY SHIPPED

A two-layer network and system-configuration stack for FreeBSD. The lower layer is the in-tree IPConfiguration daemon (DHCPv4/v6 + RA, RFC 5227 ARP, lease publish via Mach RPC). The upper layer is a port of Apple's configd — daemon name retained verbatim as configd, Mach-served as com.apple.SystemConfiguration, providing the SystemConfiguration dynamic store via MIG (configd.defs) for scutil, IPConfiguration, and GUI tooling. Companion to the freebsd-launchd-mach port.

Revision 2026-05-23 — architecture pivot. This plan originally targeted the sibling freebsd-launchd (AF_UNIX / GNUstep Distributed Objects) repo, where the daemon was renamed netconfigd. Refactored 2026-05-23 to target freebsd-launchd-mach (v2): retains Apple's daemon name configd, Mach IPC, and the original configd.defs MIG IDL. Mach service: com.apple.SystemConfiguration (acquired via bootstrap_check_in). PARTIALLY SHIPPED — the core SCDynamicStore surface is live in src/configd/, the client framework lives at src/libSystemConfiguration/ with mig-generated client stubs, and the daemon is being consumed today by IPConfiguration (sc_publish_ipv4 + sc_publish_ipv6 in src/IPConfiguration/sc_publish.c). The plugin loader and SCPreferences surface are deferred; IPConfiguration is a standalone daemon (not loaded as a configd plugin like Apple does it) and talks to configd over Mach RPC for State:/Network/Service/<UUID>/IPv4 and /IPv6 publishes. The remaining sections describe the full porting plan; everything below should be read with the understanding that the shape is now Mach-MIG, not Distributed Objects.

Status: core SCDynamicStore live, IPConfiguration consuming it PARTIALLY SHIPPED

1. Goal & non-goals

1.1 Goal

A FreeBSD live ISO that boots with launchd as PID 1, gets a working network in seconds without user intervention, and runs a SystemConfiguration-equivalent layer on top — the Apple-shape SCDynamicStore over Mach RPC for scutil, libIOKit consumers, and GUI tooling — while delegating the protocol-level work (DHCP, RA, ARP collision) to IPConfiguration, the standalone in-tree daemon that already does it. configd is the store; IPConfiguration is the protocol layer; they meet over Mach RPC.

1.2 Non-goals (this iteration)

2. Architecture: layered model

Two layers, separable in time and ownership:

+-----------------------------------+ | GUI tooling, scutil, app code | +-----------------+-----------------+ | | libSystemConfiguration.so | (mig-generated client stubs) v +----------------------+----------------------+ | configd (PARTIALLY SHIPPED) | | -------------------------------- | | - Mach service com.apple.SystemConfig- | | uration via bootstrap_check_in | | - MIG server (configd.defs, retained) | | - In-memory dynamic store: State: and | | Setup: domains, pattern subscriptions | | - SCDynamicStoreCreate / SetValue / | | CopyValue / SetNotificationKeys RPCs | | - Notification fan-out: sends mach_msg | | back to subscribed client ports on | | key updates | | - (planned) PF_ROUTE source: kernel- | | event observation into State:/Network/ | | - (deferred) SCPreferences, plugin | | loader, network-set evaluation | +----------------------+----------------------+ ^ | MIG RPC over Mach | (State:/Network/Service/ | <UUID>/IPv{4,6} publishes) | +----------------------+----------------------+ | IPConfiguration (in-tree, standalone) | | -------------------------------- | | - DHCPv4 + DHCPv6 + RA/SLAAC | | - RFC 5227 ARP probe / announce | | - Per-iface lease state machine | | - Calls sc_publish_ipv4 / sc_publish_ | | ipv6 -> libSystemConfiguration -> | | configd via Mach RPC | | | | wpa_supplicant (base, driven by wland) | +----------------------+----------------------+ | v kernel network stack

2.1 Why two layers instead of one

Apple's configd has both layers fused — the IPConfiguration agent (DHCP/RA) is loaded as a plugin inside the configd process. We split it: configd is its own process, IPConfiguration is its own process. The interface between them is the same one Apple's IPConfiguration plugin would use internally — SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} — just now reached over Mach RPC rather than in-process. From the consumer's point of view (a GUI tool reading the dynamic store) the surface is identical.

The boundary between layers is clean: IPConfiguration owns protocol actions (acquire lease, run RFC 5227 ARP, configure address); configd owns store + IPC (key/value space, subscription, notification fan-out). They communicate via the canonical SCDynamicStore RPC surface; no custom protocol.

3. Layer 1 (shipped): IPConfiguration (in-tree) + wpa_supplicant (port)

3.1 IPConfiguration as the protocol layer

Apple ships IPConfiguration as a configd plugin loaded into the configd address space. In freebsd-launchd-mach it runs as its own daemon (src/IPConfiguration/) supervised by launchd. The split is a deliberate choice — the plugin loader is deferred, and the standalone shape made it easier to iterate on the DHCP state machine and RFC 5227 ARP without dragging the rest of configd along.

3.2 wpa_supplicant from base (not ports)

Corrected. An earlier draft of this section had the security/wpa_supplicant port superseding base, arguing faster WPA3-SAE/OWE uptake and more aggressive CVE backports. The WLAN plan §3.3 rules that out: the port is the same 2.11 as base, but installs to /usr/local/sbin and shadows base for no benefit. We keep stock wpa_supplicant from FreeBSD base, untouched — not vendored into nextbsd-userland/src, not taught Mach, not added as a port. It speaks net80211 ioctls downward and a UNIX control socket upward; it never needs to know configd exists. All Mach knowledge lives in wland, which gets it for free by linking libSystemConfiguration. eapolclient (Apple's 802.1X supplicant) is not ported; WPA-Enterprise comes from wpa_supplicant's own EAP stack or not at all.

3.3 What configd IS doing today

configd is up and serving. Daemon binary at /usr/libexec/configd (TBD path; matches Apple), launchd plist publishes the com.apple.SystemConfiguration Mach service via MachServices; configd grabs the receive right via bootstrap_check_in, runs a MIG dispatch loop, and answers SCDynamicStoreCreate / SetValue / CopyValue / SetNotificationKeys / CopyKeyList over configd.defs. Notification keys cause the daemon to remember the client's notify port and send a wakeup mach_msg on key change; the client's SCDynamicStore rlsource fires.

The IPConfiguration → configd path is end-to-end: bind a lease, watch State:/Network/Service/<UUID>/IPv4 change in scutil-equivalent test tools. That's the level of "live" we're at.

4. Layer 2 (PARTIALLY SHIPPED): configd

End state: a launchd-supervised long-running daemon that publishes com.apple.SystemConfiguration, owns the SCDynamicStore, exposes the canonical configd.defs MIG surface, and (when SCPreferences arrives) reads declarative network preferences. Distinct from Apple's shape in that it does not host plugins in-process — the plugin loader is deferred. Things Apple shipped as plugins are either rolled in (IPMonitor's resolv.conf merge, future), run standalone (IPConfiguration), or unbuilt.

4.1 Dynamic store

configd publishes state to the SystemConfiguration "dynamic store" — a key-value space (keys like State:/Network/Interface/en0/IPv4) that processes subscribe to. Apple's key shape is retained verbatim. The backing store is an in-memory CF dictionary protected by a serial dispatch queue; subscribers register interest via SCDynamicStoreSetNotificationKeys (exact keys or regex patterns); the daemon sends mach_msg wake-ups to the subscriber's notify port when matching keys change.

Sources of state:

4.2 MIG surface (configd.defs)

Apple's configd.defs is the IDL, retained. mig-generated server stubs link into configd; mig-generated client stubs link into libSystemConfiguration.so. Representative routines presently wired:

4.3 SCPreferences (deferred)

Apple's SCPreferences is the persistence + commit/apply surface over preferences.plist. Header surface present in src/libSystemConfiguration/SCPreferences.c; backing store and configd-side RPCs are not yet wired. When this lands, configd will:

  1. Read preferences.plist (Apple-canonical path) via CFPropertyList.
  2. Populate Setup: keys in the dynamic store from the parsed prefs.
  3. Accept SCPreferencesCommit-shaped RPCs from clients; rewrite the plist atomically; reload Setup:; notify subscribers.

The shape is Apple-canonical — no FreeBSD-only Network.plist alternative; preferences.plist is the file.

4.4 Event sources

Source typeWatchesReaction
dispatch_source(MACH_RECV)configd's service port (from bootstrap_check_in)mig demux: dispatch routine; mutate store; fan out notifications
DISPATCH_SOURCE_TYPE_READ (planned)PF_ROUTE socketparse routing message; update dynamic store State:/Network/Interface/<iface>/...; fan out to subscribers
DISPATCH_SOURCE_TYPE_VNODE (deferred)preferences.plistreload via CFPropertyList; diff against last snapshot; rewrite Setup: keys; notify
DISPATCH_SOURCE_TYPE_SIGNALSIGTERM / SIGHUPSIGTERM: clean shutdown. SIGHUP: force config reload.

5. Repository

5.1 Layout under freebsd-launchd-mach/src/

freebsd-launchd-mach/src/
├── configd/                       The daemon. PARTIALLY SHIPPED.
│   ├── configd.c                  Service publish + MIG demux + dispatch_main
│   ├── config.defs                Apple configd.defs IDL (retained verbatim)
│   ├── config_session.{c,h}       Per-client session state, port tracking
│   ├── config_store.{c,h}         In-memory key/value store + pattern subs
│   ├── config_wire.{c,h}          MIG server stub helpers (CFData marshalling)
│   ├── config_types.h             Shared types between defs and impl
│   └── *test.c                    in-tree integration tests against the live
│                                  Mach service (configtest, listtest, patterntest,
│                                  notifytest, multitest)
│
├── libSystemConfiguration/        The client framework. PARTIALLY SHIPPED.
│   ├── SCDynamicStore.c           Public SCDynamicStoreCreate / SetValue /
│   │                              CopyValue / SetNotificationKeys; wraps mig
│   │                              client stubs into the CF API
│   ├── SCD.c, SCDMultiple.c       Bulk SCDynamicStore variants
│   ├── SCNotify.c                 Notify rlsource + callback dispatch
│   ├── SCNetworkInterface.c       Iface enumeration (planned full surface)
│   ├── SCNetworkService.c, Set.c  Network-service / set enumeration (planned)
│   ├── SCNetworkProtocol.c
│   ├── SCNetworkConfigurationInternal.{c,h}
│   ├── SCBridgeInterface.c, SCBondInterface.c, SCVLANInterface.c
│   ├── SCPreferences.c            (deferred — backing store + RPCs not wired)
│   ├── SCInternal.h
│   ├── SystemConfiguration/       public header umbrella
│   └── *test.c                    sctest, scnotifytest, scrltest, etc.
│
└── IPConfiguration/               Standalone DHCP/RA daemon. SHIPPED through iter 6.
    ├── ipconfigd.c, ipconfig.c    daemon + CLI
    ├── ipconfig.defs              IPConfiguration's own MIG IDL (separate from
    │                              configd's)
    ├── dhcp_discover.c, ra_listen.c, lease_loop.c
    ├── arp_probe.c                RFC 5227 probe + announce (iter 6)
    ├── apply_lease.c, apply_lease_v6.c
    ├── bound_state.c              fires sc_publish on BOUND
    ├── sc_publish.{c,h}           sc_publish_ipv4 / sc_publish_ipv6
    │                              -> libSystemConfiguration -> configd via Mach
    ├── mach_service.c
    └── ...

Top-level (freebsd-launchd-mach/) hosts the launchd plist for configd (com.apple.SystemConfiguration registered via MachServices in the plist; configd calls bootstrap_check_in on the published name to obtain the receive right).

5.2 Apple source provenance

The configd source is derived from Apple's configd (latest open tag configd-963.270.3). What's retained is the surface that's directly relevant to SCDynamicStore + the configd.defs IDL; the bulky plugin tree (IPMonitor, KernelEventMonitor, LinkConfiguration, PreferencesMonitor, SCNetworkReachability, InterfaceNamer, SimulatorSupport, QoSMarking) is not present. Files that are in-tree retain their Apache 2.0 headers per-file.

6. Locked architectural decisions

DecisionChoice
Target kernelFreeBSD 14.x and 15.x. No Linux, no NetBSD.
Daemon nameconfigd — Apple-canonical, retained verbatim. NOT renamed to netconfigd (that's the sibling repo's choice).
DHCPv4 / DHCPv6 / RA / SLAAC / ARPIn-tree IPConfiguration (Apple's port). Standalone daemon, not loaded as a configd plugin. RFC 5227 ARP probe / announce shipped in iter 6.
WLAN authenticationStock wpa_supplicant from base, driven by wland. Not the port. Apple's eapolclient is not ported.
IPCMach IPC. Apple's configd.defs MIG IDL is retained verbatim. mig-generated server stubs in configd, client stubs in libSystemConfiguration. NOT Distributed Objects, NOT AF_UNIX (that's the sibling repo).
Service publishMach service com.apple.SystemConfiguration, registered in the launchd plist MachServices dict; bootstrap_check_in hands the receive right to configd at startup.
Notification fan-outThe daemon sends a wake-up mach_msg back to subscribed clients' notify ports on key change. The client's SCDynamicStore rlsource demuxes and fires the user callback.
Event looplibdispatch dispatch sources. dispatch_source(MACH_RECV) on the service port for inbound RPC; plus PF_ROUTE / vnode sources as features land.
Plist parsinglibCoreFoundation CFPropertyListCreateWithData (XML + binary).
Source of truth for declarative configpreferences.plist (Apple-canonical path), when SCPreferences lands. No rc.conf parser. No FreeBSD-only Network.plist file.
Plugin loaderDeferred. IPConfiguration runs standalone; other Apple plugins are not built.
License (top-level)BSD-2-Clause. Apple configd files retain Apache 2.0 per-file.
Build platformFreeBSD only, inside the same VM-action chroot the launchd build uses.

7. File-by-file plan (src/configd/ + src/libSystemConfiguration/)

Apple source baseline: configd-963.270.3 (~289 files, ~5.5 MB pre-pruning). What's not in-tree: the plugin tree (IPMonitor, KernelEventMonitor, LinkConfiguration, PreferencesMonitor, SCNetworkReachability), InterfaceNamer, SimulatorSupport, QoSMarking, AirPort, Apple-Wireless-Diagnostics, Swift test harnesses, Xcode build infra.

7.1 Not imported

7.2 Status by component

ComponentIn-tree atStatusNotes
configd daemon coresrc/configd/configd.c + config_session.c + config_store.c + config_wire.cSHIPPEDdispatch_main + MIG demux on the com.apple.SystemConfiguration service port. Session-per-client state. Store backs State: + Setup:; pattern subs via regex.
configd.defs IDLsrc/configd/config.defsSHIPPEDApple IDL retained. Drives both server stubs (in configd) and client stubs (in libSystemConfiguration).
SCDynamicStore (client)src/libSystemConfiguration/SCDynamicStore.c + SCD.c + SCDMultiple.c + SCNotify.cSHIPPEDWraps mig client stubs into CF API. SCDynamicStoreCreate / SetValue / CopyValue / SetNotificationKeys / CreateRunLoopSource all functional.
libSystemConfiguration enumeration surface (SCNetworkInterface, Service, Set, Protocol)src/libSystemConfiguration/SCNetwork*.cPARTIALHeader surface present; runtime gets fuller as configd's Setup: side comes online.
SCBridgeInterface, SCBondInterface, SCVLANInterfacesrc/libSystemConfiguration/SCBridge/Bond/VLAN*.cPARTIALCompose against FreeBSD's ifconfig surface where possible.
SCPreferencessrc/libSystemConfiguration/SCPreferences.cDEFERREDHeader present, backing store + configd-side RPCs not wired.
IPConfiguration (lease publish)src/IPConfiguration/sc_publish.c, sc_publish.hSHIPPEDCalls SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} via libSystemConfiguration. This is the working proof that the daemon serves real consumers.
IPMonitor (resolv.conf merge)not importedFUTUREOnce multiple services need to compose into one resolv.conf, port the Apple plugin's merge logic into configd directly (no plugin loader).
KernelEventMonitor (PF_ROUTE)not importedFUTURERewrite as a configd-internal source: DISPATCH_SOURCE_TYPE_READ on PF_ROUTE; populate State:/Network/Interface/<iface>/....
SCNetworkReachabilitynot importedFUTUREPort the public API; PF_ROUTE for change events; serve over MIG.
scutil CLInot importedFUTUREPort as a libSystemConfiguration client. --show / --get / --set / --watch.
nwi (network-information)not yet importedFUTUREMostly pure data structures; port when a consumer needs it.

8. FreeBSD-only deltas (vs Apple's Darwin-tied configd)

FeatureApple's configd doesThis port (FreeBSD)
DHCP / RA / ARPLoaded as the IPConfiguration plugin inside the configd process.Runs as its own daemon (src/IPConfiguration/). Same Apple code lineage, same SCDynamicStore publish surface; just out-of-process. Talks to configd over Mach RPC instead of in-process function calls.
Kernel iface eventsPF_SYSTEM + KEV_NETWORK_CLASS + kern_eventPF_ROUTE socket. Planned configd-internal source; observation-only (IPConfiguration owns its own PF_ROUTE feed for action).
Service IPCMach ports + XPC + bootstrap serverSame shape. Mach IPC retained; configd.defs retained as the MIG IDL; service published as com.apple.SystemConfiguration via bootstrap_check_in. (XPC is also available in this repo; configd just doesn't use it — it's a raw MIG server.)
WLAN authAirPort framework + eapolclientStock wpa_supplicant from base, driven by wland. No eapolclient.
Iface namingInterfaceNamer plugin: IOKit USB/PCI introspectionFreeBSD kernel handles iface naming. Drop the plugin. Iface metadata (USB/PCI introspection) is separately available via libIOKit over hwregd.
Plugin loadingMach host port + bundle dlopen at startupDeferred. IPConfiguration is its own daemon; other Apple plugins are unbuilt or rolled in directly.
Build-system gatesiOS / macOS / sim / catalyst #if TARGET_OS_*One target (FreeBSD). Apple gates dropped.

9. Dependencies

Build-time: clang, lld (FreeBSD base); mig (in-tree, builds the server + client stubs from config.defs); pkgconf; system-domain headers/libraries at /System/Library/.

Runtime (on the ISO):

10. launchd integration

10.1 IPConfiguration plist (in place)

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>Label</key>             <string>com.apple.IPConfiguration</string>
    <key>ProgramArguments</key>  <array>
        <string>/usr/libexec/IPConfiguration</string>
    </array>
    <key>RunAtLoad</key>         <true/>
    <key>KeepAlive</key>         <true/>
</dict>
</plist>

IPConfiguration runs in foreground supervised by launchd; KeepAlive=true respawns it if it dies. Apple-canonical Label.

10.2 configd plist (Mach-service shape)

<plist version="1.0">
<dict>
    <key>Label</key>            <string>com.apple.configd</string>
    <key>ProgramArguments</key> <array><string>/usr/libexec/configd</string></array>
    <key>RunAtLoad</key>        <true/>
    <key>KeepAlive</key>        <true/>
    <key>MachServices</key>     <dict>
        <key>com.apple.SystemConfiguration</key>
        <true/>
    </dict>
</dict>
</plist>

launchd registers the com.apple.SystemConfiguration Mach service at boot. configd calls bootstrap_check_in("com.apple.SystemConfiguration", &recv_port) at startup to obtain the receive right. Until configd is up, RPCs from libSystemConfiguration clients block at bootstrap_look_up (or get a queued send right depending on launchd's OnDemand semantics — tracking this in iter wash). After check-in, configd runs dispatch_source(MACH_RECV) on the port and dispatches incoming MIG messages.

11. preferences.plist schema (DEFERRED — SCPreferences)

One canonical declarative configuration file at Apple's path. The GUI tooling reads/writes it via SCPreferences*; configd loads it into Setup: keys and re-evaluates on commit. The shape below is illustrative — final shape will follow Apple's preferences.plist schema (network-service-keyed, with NetworkServices, Sets, System dicts). Until SCPreferences lands, no plist is consulted; the auto-DHCP path through IPConfiguration runs unaided.

The example below is the original FreeBSD-only sketch from the sibling repo's plan, preserved for the data-model intent only:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>Hostname</key>
    <string>my-host</string>

    <key>Interfaces</key>
    <dict>
        <key>em0</key>
        <dict>
            <key>Method</key> <string>DHCP</string>
        </dict>

        <key>em1</key>
        <dict>
            <key>Method</key> <string>Static</string>
            <key>IPv4</key>
            <dict>
                <key>Address</key> <string>192.168.1.10/24</string>
                <key>Router</key>  <string>192.168.1.1</string>
            </dict>
        </dict>

        <key>wlan0</key>
        <dict>
            <key>Method</key> <string>WPA</string>
            <key>WPA</key>
            <dict>
                <key>ConfigFile</key> <string>/etc/wpa_supplicant.conf</string>
            </dict>
            <key>IPv4</key>
            <dict>
                <key>Method</key> <string>DHCP</string>
            </dict>
        </dict>
    </dict>

    <key>DNS</key>
    <dict>
        <!-- Optional. If absent, DNS is taken from DHCP. -->
        <key>Servers</key>
        <array>
            <string>1.1.1.1</string>
            <string>1.0.0.1</string>
        </array>
        <key>Search</key>
        <array><string>example.com</string></array>
    </dict>
</dict>
</plist>

Empty / absent preferences.plist → IPConfiguration's defaults apply (auto-DHCP everything, RA on every iface). The no-config-needed default; today's live behavior.

Per-iface dict missing → IPConfiguration's defaults apply for that iface. A user who wants em0 to NOT auto-DHCP would express that through the SCPreferences API once it lands.

11.1 Schema versioning

The Apple preferences.plist ships an explicit version key in its top-level dict. The port follows.

12. scutil CLI tool (FUTURE)

Apple's scutil is the system-configuration shell. Ported as a libSystemConfiguration client (which means it talks to configd over the same Mach RPC surface as every other client). Initial command set when it lands:

The Apple interactive store-shell mode is in scope — it builds on the same MIG surface configd already speaks, so it should be straightforward.

In the meantime, the in-tree test programs (configtest, listtest, patterntest, notifytest, multitest, sctest, scnotifytest) cover most of what an early scutil would expose.

13. Licensing

Top-level BSD-2-Clause; Apple configd source files retain their Apache 2.0 headers per-file (inbound=outbound). New code is BSD-2-Clause with SPDX headers.

SourceLicenseHow we handle it
Apple configd-963.270.3Apache 2.0 (Apple OSRef)Keep Apple header verbatim. Files stay Apache regardless of top-level.
Apple IPConfiguration (Apple OSRef)Apache 2.0Keep Apple header verbatim; same handling.
libdispatch, libCoreFoundation, libxpc (Apple OSRef, in this repo's tree)Apache 2.0 with Runtime Library ExceptionPer-file Apache; listed in NOTICE.
wpa_supplicant (base, separate process)BSD-3-ClauseAlready in base; not linked into configd. Listed in NOTICE when WLAN ships.
This repo's new codeBSD-2-ClauseEach new file gets a BSD-2-Clause SPDX header.

14. Phased delivery

Phase 0 — repo scaffold + Apple source import DONE

Phase 1 — configd daemon: MIG service publish + SCDynamicStore DONE

Phase 2 — libSystemConfiguration client framework DONE

Phase 3 — first real consumer: IPConfiguration sc_publish DONE

Phase 4 — SCPreferences + Setup: keys PLANNED

Phase 5 — PF_ROUTE source + KernelEventMonitor-equivalent PLANNED

Phase 6 — scutil CLI PLANNED

Phase 7 — SCNetworkReachability for apps PLANNED

Phase 8+ — optional, demand-driven FUTURE

15. Open questions

RESOLVED — Daemon name. configd — Apple-canonical, retained. The sibling freebsd-launchd (AF_UNIX/DO) repo renames to netconfigd; this Mach-IPC repo does not.
RESOLVED — IPC mechanism. Mach IPC. configd.defs retained as the MIG IDL verbatim. mig-generated server stubs in configd; mig-generated client stubs in libSystemConfiguration.so. Service published as com.apple.SystemConfiguration via bootstrap_check_in.
RESOLVED — Lease publish surface. IPConfiguration calls SCDynamicStoreSetValue on State:/Network/Service/<UUID>/IPv{4,6} via libSystemConfiguration — the Apple-canonical key shape, the Apple-canonical API. Shipped at src/IPConfiguration/sc_publish.c.
RESOLVED — DHCP/RA/ARP daemon. In-tree IPConfiguration (Apple source lineage), running as a standalone daemon — not loaded as a configd plugin. RFC 5227 ARP probe/announce shipped in iter 6.
RESOLVED — Repo layout. src/configd/ and src/libSystemConfiguration/ under freebsd-launchd-mach.
RESOLVED — Daemon binary path. /usr/libexec/configd for the daemon (matches Apple); /usr/sbin/scutil for the CLI client (when ported).
Q. /etc/resolv.conf ownership. Apple's IPMonitor plugin watches DNS-related State: keys and writes resolv.conf via merging policy. Port that logic into configd directly when multi-service DNS composition matters (today, single-service IPConfiguration writes resolv.conf via its own path).
Q. SCPreferences storage format. Apple's preferences.plist ships a specific shape (NetworkServices / Sets / System dicts, version key). Port the schema as-is or simplify for the FreeBSD-only world? Lean Apple-as-is for ABI affinity with macOS scutil dumps.
Q. WLAN credentials storage. Moved — this is now WLAN plan Q2, and it is wland's question, not configd's. Short version: plaintext either way, because there is no keychain and none is started. The only choice is which plaintext file — /etc/wpa_supplicant.conf (0600, root) or a root-owned preferences.plist under /Local/Library/Preferences/SystemConfiguration. Not a security difference, only an architectural one. A real keychain is greenfield and its own multi-month project (Keychain plan).
Q. Plugin loader, ever? Currently every Apple "plugin" is either rolled into configd or out as a standalone daemon. If a third party wants to extend configd at runtime without modifying it, the plugin loader becomes interesting. Until then, deferred.
Q. nwi (network-information) component. Apple ships libsystem_network's nwi as a small read-only mmaped state file that configd writes. Useful for fast in-process reachability heuristics without IPC. Port when an in-process consumer cares.

16. References


Revision history.
2026-05-23 — Architecture pivot: refactored from the sibling AF_UNIX/DO track to freebsd-launchd-mach (v2, the Mach-IPC track). Daemon name restored to Apple-canonical configd; configd.defs MIG IDL retained verbatim; Mach service com.apple.SystemConfiguration registered via bootstrap_check_in; libSystemConfiguration.so client framework hosts the mig-generated client stubs. PARTIALLY SHIPPED: the core SCDynamicStore RPC surface is live and consumed by IPConfiguration's sc_publish_ipv4 / sc_publish_ipv6. SCPreferences, PF_ROUTE source, scutil CLI, and SCNetworkReachability are planned in subsequent iterations. The plugin loader is deferred indefinitely; IPConfiguration runs as a standalone daemon and reaches configd over Mach RPC for State:/Network/Service/<UUID>/IPv{4,6} publishes.
(previous) — Original plan filed against the sibling freebsd-launchd (AF_UNIX/DO) track; daemon renamed netconfigd; service-to-service IPC via GNUstep Distributed Objects over AF_UNIX. Superseded for this repo.