Socket-transport cmd space (off_14 ids) from live capture: 1101/1307/1705/1707 + host_probe3

This commit is contained in:
kfj001 committed 2026-10-16 00:14:42 +00:00
1 parent 2cdc274fe3
commit 213a0518d6
7 files changed
+401 -60

No files matched your search

+38 -12
View File
@@ -110,6 +110,8 @@ Null/empty payload ⇒ `len == 0`, `crc == ""`, no `dataArea` key.
## 4. `CommunicationCmd` (raw → name)
`off_8` values (the enum's first id field):
```
0x00 queryDeviceInfo 0x13 pairPower 0x26 smartLoad2
0x01 networkInfo 0x14 processPairPower 0x27 rebootDevice
@@ -132,6 +134,17 @@ Null/empty payload ⇒ `len == 0`, `crc == ""`, no `dataArea` key.
```
(missing: 0x09, 0x1b, 0x2c, 0x31 — not surfaced as instances.)
**Two id spaces.** `CommunicationCmd::cmd(cmd, mode)` (0xc92894) returns the
*second* id field (`off_14` in the pool) for `socket`/`bluetooth`/`local`
modes and throws `"do not support http communication"` for `http`. The
socket-transport ids live in `SOCKET_CMD_TYPE`
(`protocol/commands.py`) — e.g. `queryDeviceInfo → 1101 (0x44D)`,
`deviceApowerInfo → 1307 (0x51B)`, `bms → 1705`, `ems → 1707`. The `off_8`
values above are **not** used on the socket/BLE wire. Verified live: a
PCAPdroid capture of the working app shows
`{"cmdType":1101,"equipNo":"00000000",…}` with the S1-plaintext-first
framing (§5).
## 5. Encryption — `communication_center/core/encryption.dart`
**`generateSecretKey(String equipNo)`** = hex of `(sum(utf8(equipNo)) & 0xFF)` (via
@@ -167,6 +180,15 @@ So requests are `S1 || transform(S2)` (split at the computable header
length) while responses are `s || 0x58 || transform(tail)` (split at the
second `0x58` marker). Both halves share the one additive stream.
Live corroboration (2026-10-15, PCAPdroid capture of the working app): a
request frame opens with the ASCII header
`{"cmdType":1101,"equipNo":"00000000",` — plaintext `S1` first, exactly as
derived, with the socket-space id (§4). A second frame shows
`{"cmdType":1102,"equipNo":"1006005A03X25160132",` (larger payload,
direction under analysis — see §8). Note the captures were exported as
text, so non-UTF-8 bytes were replaced with U+FFFD and only the ASCII
prefixes survive; a binary `.pcap` export is still wanted.
## 6. Checksums & byte order
- **CRC16** (`utils/crc16.dart`): init `0xFFFF`, poly `0xA001` (reflected), i.e.
@@ -237,22 +259,26 @@ authS2C=2 "fwh/s2c/auth/" mngC2S=5 "fwh/c2s/mng/" deviceS2C "fwh/s2c/
### Empirical — live aGate on its SoftAP (2026-10-13, from a client on `10.100.1.0/24`)
Full TCP sweep of `10.100.1.1` (ports 1–65535): exactly **two** ports open — **53** and **9000**. No 80/443, no web UI, and **18000 (`0x4650`) is closed** on this unit.
Full TCP sweep of `10.100.1.1` (ports 1–65535): exactly **two** ports open — **53** and **9000**. No 80/443, no web UI, and **18000 (`0x4650`) is closed** on this unit. No `9000` reference exists anywhere in the app (Dart or Java) — but see the 2026-10-15 update below.
- **Port 53** — authoritative, *closed* DNS: well-formed `NXDOMAIN` for everything
(even `example.com`), no PTR for `1.1.0.100.in-addr.arpa`, no forwarding (the SoftAP
is an island). Serves some local name pattern we haven't identified yet.
- **Port 9000** — a **length-prefixed framing service** (int16LE length), consistent
with the app's socket layer:
- every TLS `ClientHello` gets `UNEXPECTED_EOF` mid-handshake — first two bytes
`16 03` = int16LE `790`, so the decoder waits for a 790-byte frame that never
completes, then closes on idle;
- cleartext HTTP `GET` (`47 45` = `17735`) hangs forever (read timeout).
- Earlier probes are superseded: they used an int16LE length prefix (the
socket layer sends **raw**), the old `transform(b) || a` order (correct
is `a || transform(b)` — §5), a truncated `equipNo`, and default radix
16. All are corrected in the current PoC; see `BATTERY_POC.md` for the
host probe recipe with the true SN.
- **Port 9000** — accepts TCP, reads one frame, answers zero bytes, closes —
for *every* probe (TLS ClientHello, HTTP GET, MQTT CONNECT, exact-spec
envelopes raw/split/length-prefixed, greeting-first reads).
### Update (2026-10-15) — socket cmd space + live capture
All pre-2026-10-15 probes used `off_8` ids (`25/0/29/30`) and were dropped
silently — the socket transport speaks the `off_14` id space (§4), so the
device saw unknown commands. A PCAPdroid capture of the working app shows
real socket frames: `{"cmdType":1101,…}` (queryDeviceInfo, empty SN) and
`{"cmdType":1102,"equipNo":"1006005A03X25160132",…}` (922 B). Open:
dst IP:port + direction per frame (need capture metadata / full `.pcap`),
the meaning of `1102` (no pool cmd maps to `0x44E`), and the 17-char
`equipNo` (sub-device? battery unit? reply convention?). Current probes
use socket-space ids (`1101/1307/1705/1707`) via `scripts/host_probe3.py`.
## 9. Bluetooth (BLE) transport — `communication_center/bluetooth`