Update protocol docs with server-side findings from RE

Add server-side implementation notes to KVM_PROTOCOL.md for KeyEvent
encryption support, ScreenSetPosition/ScreenCalibration handling,
SetScreenUILang desync risk, QoS bandwidth throttling, and PowerControl
dispatch. Add server-side architecture section to MOUNT_PROTOCOL.md
documenting ikvm_vmass.ko kernel module internals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Davíð Steinn Geirsson 2026-03-12 13:34:24 +00:00
parent 84b22693ce
commit 400d08bc72
2 changed files with 83 additions and 7 deletions

View file

@ -787,10 +787,18 @@ Total: 10 bytes.
### KeyEvent (type 0x04) — ATEN Extended
**IMPORTANT: Keyboard events are NEVER encrypted.** Unlike PointerEvents, the
`Sendkey()` function always sends keyboard events in cleartext. The RFBKeyboard
object does allocate an `RFBKMCryto` instance (at this+0x20), but `Sendkey()`
never calls it. Only mouse events support AES-128-CBC encryption.
**IMPORTANT: Keyboard events are NEVER encrypted by the client.** Unlike
PointerEvents, the `Sendkey()` function always sends keyboard events in
cleartext. The RFBKeyboard object does allocate an `RFBKMCryto` instance
(at this+0x20), but `Sendkey()` never calls it.
**Server-side note**: The server's KeyEvent handler at `0xf8c4` *does* check the
encryption flag byte and supports decrypting AES-encrypted keyboard events
(same AES-128-CBC scheme as mouse events). If the first byte after type is
non-zero, the server treats the remaining 16 bytes as AES ciphertext. However,
since the client never encrypts keyboard events, this code path is never
exercised in practice. A custom client could encrypt keyboard events for
additional security — the server will handle them correctly.
```
┌─────────────────────────────────┐
@ -1179,6 +1187,11 @@ Total: 9 bytes. Sends a screen position/offset to the server. The x and y
values are packed as a 64-bit value split into two 32-bit words.
(`RFBScreen::ScreenSetPosition` at 0x001189b0)
**Server-side note (WPCM450/Hermon)**: The server handler at `0xf7b0` reads the
two u32 values and discards them. This message has no effect on the Hermon
server — the VCD hardware captures the full video signal regardless of
position offset.
### ScreenCalibration (type 0x17)
```
@ -1190,6 +1203,12 @@ values are packed as a 64-bit value split into two 32-bit words.
Triggers a screen recalibration on the BMC.
**Server-side note (WPCM450/Hermon)**: Type 0x17 is NOT present in the server's
ProtocolHandler dispatch switch. The server does not handle this message type.
Sending it will trigger the default case and print "ProtocolHandler: Error
message type !!". This message type may only be supported on other BMC
chipsets (AST, Pilot3).
### SetPowerOnOff (type 0x1A)
```
@ -1214,6 +1233,13 @@ All four JNI functions call `SetPowerOnOff(action)` through the RFBScreen vtable
(vtable index 7, offset 0x38 from vtable base). `RFBScreen::SetPowerOnOff` at
0x00118900 simply writes: type 0x1A, then the action byte, then flushes.
**Server-side note (WPCM450/Hermon)**: The server handler at `0xfae4` dispatches
to libutility.so functions: code 0 → `UtilPowerDown()`, 1 → `UtilPowerUp()`,
2 → `UtilPowerReset()`, 3 → `UtilSoftPowerDown()`. Any other code prints
"Error Power Control Request!!". No response is sent to the client. Power
control requires no special permission — it is in the "always allowed" group
in the server's permission filter (alongside KeepAlive, SetBandwidth, etc.).
### ScreenSetInfo (type 0x32)
```
@ -1311,6 +1337,14 @@ the Java application and BMC firmware (video quality level, compression ratio,
and bandwidth limit are the likely interpretations based on the Java UI
option frames).
**Server-side note (WPCM450/Hermon)**: The server handler at `0xfa10` reads
all 3 u32 values and passes them to `SetBandwidthLimits` at `0x13128`, which
configures the stream's read and write bandwidth counter objects. These counters
implement `select()`-based throttling — when bandwidth exceeds the configured
limit, the stream write functions sleep to enforce the cap. The 3 parameters
map to: `limit1` (read bandwidth), `limit2` (write bandwidth), `period`
(time window for measurement).
### GetScreenUI (type 0x3C)
```
@ -1349,6 +1383,12 @@ Java side through the vtable. When the flag is zero (default), only 5 bytes
are sent (type + lang_id). When non-zero, 9 bytes are sent (type + lang_id +
lang_sub).
**Server-side note (WPCM450/Hermon)**: The server handler at `0xfaa4` always
reads 2 u32 values (8 bytes of payload), regardless of any FW protocol flag.
A client sending only 5 bytes (1 u32) will cause the server to block waiting
for the second u32, potentially causing a protocol desync. For Hermon servers,
always send both u32 values (9 bytes total).
The `setScreenUILang` JNI method at 0x00121b00 takes two int parameters from
Java and calls `ProcSetScreenUI(param_3, param_4)` through the RFBProtocol
vtable (offset 0x30).

View file

@ -49,14 +49,50 @@ is the more interesting and complex one.
▼ │
┌──────────────────────────────────────────────────────────┐
│ BMC Firmware │
│ - Presents virtual USB device to managed server │
│ - Forwards SCSI commands as CBW over TCP │
│ - Receives data + CSW responses │
│ - Virtual media daemon (userspace) │
│ - Reads CBW from ikvm_vmass.ko char device │
│ - Writes data + CSW responses back │
├──────────────────────────────────────────────────────────┤
│ ikvm_vmass.ko (kernel module, WPCM450 USB 2.0 UDC) │
│ - USB VID=0x0EA0 (ATEN), PID=0x2168 │
│ - Bulk-Only Mass Storage on EP1/EP2 (LUN 0) │
│ - Optional second LUN on EP4/EP5 (LUN 1) │
│ - 1.3MB coherent DMA buffer for USB transfers │
│ - 640KB SCSI data buffer per LUN │
│ - USB descriptors supplied by userspace via ioctl │
└──────────────────────────────────────────────────────────┘
```
---
## Server-Side Architecture (WPCM450/Hermon)
The BMC-side virtual media implementation uses the `ikvm_vmass.ko` kernel
module (source: `wpcm450_vmass.c`, NOT stripped, 369 symbols). The module
implements a USB 2.0 device controller driver for the WPCM450's on-chip USB
hardware. Key details from server firmware RE (`REVERSING_SERVER.md`):
- **USB identity**: ATEN VID=0x0EA0, PID=0x2168
- **Dual-LUN**: Supports up to 2 logical units (devices). LUN 0 uses EP1 (OUT)
and EP2 (IN), LUN 1 uses EP4 (OUT) and EP5 (IN).
- **Descriptor injection**: USB descriptors (0x520 bytes) are provided by the
userspace daemon via ioctl `0xC0085501`. The client's USB descriptor data
(sent during plug-in) is forwarded to the kernel module to define the virtual
device identity presented to the host.
- **Data flow**: The userspace daemon reads CBW packets from the char device
(31-byte CBW triggers SCSI dispatch), processes them, and writes response
data + CSW back. The kernel module handles USB transfer mechanics, DMA,
and endpoint service.
- **SCSI dispatch in kernel**: The module parses CBW opcode to determine
transfer direction and length — READ_10 (0x28) and READ_CD (0xBE) are IN,
WRITE_10 (0x2A) and opcode 0x20 are OUT, all others have no data phase.
- **Speed negotiation**: Full-speed (64 byte packets) or high-speed (512 byte
packets), auto-negotiated during USB enumeration.
- **3 ioctls**: `0xC0085501` (register/set descriptors), `0x40085502`
(disconnect USB), `0x40085503` (connect USB).
---
## Connection Setup
### 1. Initialization