r/vitahacks • u/IronmanX75 • 12h ago
AI assisted Carplay on vita update!!
Background: VitaPlay is a homebrew wireless CarPlay receiver for the PS Vita (C/VitaSDK, ported from the PlayPort/DiPlay/xcertplay lineage). It already works — video, touch, controls, and MFi auth (offline keys) all run on the Vita. The catch: wireless CarPlay starts with a Bluetooth handshake (iAP2), and the Vita’s stock Bluetooth can’t initiate it. So today a nearby Linux/Mac box does the BT pairing and hands the phone to the Vita over Wi‑Fi. The goal of this stretch was to do that bootstrap on the Vita, so there’s no helper PC — you just open the app.
What reverse-engineering SceBt (the Vita’s BT module, FW 3.65) turned up:
- The Vita’s Bluetooth is a responder only. The function that sends an outbound L2CAP connection request has zero callers — it’s dead code. The Vita can pair, but the stack never “dials out” the way a CarPlay accessory has to.
- The one profile that would do outbound RFCOMM (OPP) is stubbed on 3.65. HFP is stubbed too. So the obvious “just call the SPP API” route is a dead end.
I RE’d this by disassembling a physical RAM dump of the loaded module — the on-disk firmware is encrypted, but the live kernel copy isn’t.
What I built (a taiHEN kernel plugin):
- Hooked SceBt’s incoming L2CAP handler — full visibility into every L2CAP packet.
- Proved L2CAP injection by sending an echo request to the connected iPhone and catching my own payload echoed back.
- Opened an L2CAP channel to the iPhone’s RFCOMM PSM by calling that orphaned-but-functional connection-request sender directly. The iPhone accepted it.
- The hard part: the Vita’s stack ignored my channel’s config, because it only tracks channels it opened itself (which it never does). So I got SceBt to adopt my hand-opened channel — create a channel object with SceBt’s own allocator, patch two fields — and SceBt then ran the entire L2CAP config negotiation (including MTU) by itself, automatically.
Result: a fully open, SceBt-managed L2CAP channel to the iPhone’s RFCOMM — the transport layer iAP2/CarPlay bootstrap rides on — with zero crashes. It’s idle only because the iPhone (the RFCOMM server) is waiting for the Vita to start RFCOMM, which is the next step.
Next: speak RFCOMM (TS 07.10) on that channel, open the data channel for the iAP2 service, and feed it into the already-ported iAP2 layer. If that lands, the Vita does the whole CarPlay bootstrap solo and the helper PC goes away.
Caveat: this is all FW‑3.65‑specific, held together with reverse-engineered offsets — research-grade, not a release. But the Bluetooth path everyone (me included) assumed was impossible on the Vita turns out to be reachable.
Happy to answer questions.
Methodology note: this was AI-assisted reverse engineering. I (Claude, via Claude Code) read the SceBt disassembly, worked out the function offsets and struct fields, and wrote the taiHEN plugin; OP drove the whole thing — the project and idea, the direction calls at each fork, the hardware, and every on-device test that turned a theory into a confirmed result. The RE is only as good as the logs coming back from a real Vita, and that half was all OP.
