Socket-transport cmd space (off_14 ids) from live capture: 1101/1307/1705/1707 + host_probe3
This commit is contained in:
1 parent
2cdc274fe3
commit
213a0518d6
7 files changed
+401
-60
No files matched your search
+38
-12
@@ -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`
|
||||
|
||||
|
||||
Reference in new issue
Block a user