mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 11:08:25 +00:00
The transport dialled every peer on one configured PSM and bound its own listener to the same one. That works only because BlueZ lets an application choose the PSM it binds, and BlueZ is the exception: Android's listenUsingInsecureL2capChannel and macOS's CBPeripheralManager.publishL2CAPChannel both return an OS-assigned PSM the application cannot request. A dialer cannot guess it, and before a connection exists there is no channel to be told it on other than the advertisement. So the PSM becomes a property of the seam rather than a per-backend assumption. BleIo::listen reports the PSM it actually bound, start_advertising takes the PSM to advertise, and BleScanner yields a ScanAdvert -- address, plus PSM and RSSI when the backend can supply them -- instead of a bare address. The scan/probe loop keeps the learned PSM per address alongside the probe-cooldown map it already maintains and passes it into the existing connect(addr, psm), falling back to the configured PSM when a peer advertises none. The wire layout is a protocol decision and is documented in psm.rs with the byte budget that forces it. A legacy advertising PDU carries 31 bytes; flags take 3 and the 128-bit FIPS service UUID takes 18, which leaves too little for service data keyed on that same 128-bit UUID. The PSM is therefore keyed on the 16-bit UUID 0x9C90, the FIPS UUID's leading 16 bits through the Bluetooth base UUID, costing 6 bytes for a total of 27. The budget is a const assertion, so a change back to a 128-bit key fails the build rather than the radio. It rides the primary advertisement, never the scan response, because a scan response needs an active-scan round trip that drops asymmetrically across chipsets. The BlueZ backend now advertises and reads that service data, which is what lets a BlueZ node tell an Android peer where to dial and learn the peer's OS-assigned PSM in return. Emitting it costs the local_name, which no longer fits the budget. Nothing reads a peer's advertised name -- discovery keys on the service UUID alone, here and on maint -- so dropping it does not affect which nodes can find each other. Compatibility with deployed nodes is unchanged in both directions. BlueZ listeners still bind the configured PSM, so an existing node dialling that PSM still connects. A peer that advertises no service data yields psm: None and is dialled at the configured PSM exactly as before. BleConfig::psm keeps its type, default and meaning; only its doc comment changes to say it is now what to bind and what to dial when a peer advertises nothing. BlueZ shortens a base-range 128-bit UUID to its 16-bit form before building the AD structure, so the service data goes out as the 6-byte AD type 0x16 the layout requires rather than the 20-byte 0x21 form, and the advert stays inside the PDU. Read in BlueZ 5.72: bt_string_to_uuid tests is_base_uuid128 first (lib/uuid.c), and serialize_service_data emits BT_AD_SERVICE_DATA16 for a 2-byte UUID (src/shared/ad.c). This was the open question the change was held on. The BlueZ implementation moves out of io.rs into io_linux.rs at the same time. io.rs now holds only what is platform-neutral -- the traits, ScanAdvert and the mock -- so a new backend is a new io_<platform>.rs beside it rather than another arm inside the shared file. The move is content-preserving: the only changes to the relocated code are three import paths and two rustfmt reflows caused by the dedent. Co-authored-by: Arjen <18398758+Origami74@users.noreply.github.com>
Reference
Information-oriented technical descriptions for lookup on demand. Reference content describes what is: wire formats, configuration keys, command-line flags, control-socket commands, default values, file paths, exit codes. It is consulted, not read end-to-end.
Reference is austere by design: minimal narrative, no opinions, no guidance on when to use a feature. The "why" lives in design/; the "how do I accomplish X" lives in how-to/.
Available Reference
| Document | Scope |
|---|---|
| wire-formats.md | All FMP and FSP message byte layouts, encapsulation walkthrough |
| configuration.md | Full YAML configuration reference for the daemon and gateway |
| security.md | nftables baseline, peer ACL, cryptographic primitives, rekey defaults, threat-resistance matrix |
| nostr-events.md | Kind 37195 advert, Kind 21059 traversal signaling, Kind 10050 inbox relays |
| transports.md | Per-transport statistics counter inventory |
| control-socket.md | Line-delimited JSON control protocol for the daemon and gateway |
| native-api.md | Native datagram API: the Rust surface, addressing and ports, errno table, ceilings, line protocol, command reference |
| cli-fips.md | fips daemon CLI: options, exit codes, environment, files |
| cli-fipsctl.md | fipsctl control-client: subcommands, options, exit codes |
| cli-fipstop.md | fipstop live-status TUI: tabs, keybindings |
| cli-fips-gateway.md | fips-gateway service CLI: options, exit codes, files |