Add LUN field and handled/ignored status to SCSI debug log lines so
unknown opcodes (silently accepted per firmware behavior) are clearly
distinguishable from handled commands that return no data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GET_EVENT_STATUS_NOTIFICATION was returning media status byte 0x00 (no
media present) instead of 0x02 (media present, door/tray closed). This
caused the host kernel to think the disc was ejected after initial reads,
triggering USB bus resets that cascaded to the shared IPMI Virtual CDROM
interface.
Also properly handle Notification Class Request field (CDB byte 4):
class_request=0 now returns 4-byte NEA response matching the original
client behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix command loop to check PDU type before length (matching the original
client's State_Fn_RX_PDU_TAG dispatch order). Previously length==0x1F
was checked first, which could misparse known PDU types as SCSI CBWs.
Drain payload bytes for keepalive and other known PDU types to prevent
stream desync if the BMC sends them with a non-zero length field.
Add structured logging via the log crate: SCSI commands log opcode name,
endpoint, tag, transfer/response sizes, status, and elapsed time.
READ_10/READ_12 additionally log LBA and sector count. Protocol events
(keepalives, mount status, unknown PDUs) are logged at trace/debug level.
Enable with RUST_LOG=debug (or RUST_LOG=trace for PDU headers).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SocketAddr::parse only accepts IP addresses, not hostnames. Switch to
ToSocketAddrs to match the KVM connection code and support hostnames.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The async-std runtime initialized by rfd's xdg-portal file dialog
pollutes the thread state, causing EAGAIN on subsequent blocking
socket I/O. Spawning the mount session on a fresh thread avoids this.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tokio in the dependency tree causes zbus (used by Slint for XDG
settings) to expect a tokio runtime, panicking on startup. async-std
avoids this conflict.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents modifier keys from getting stuck on the BMC when the
window loses focus (e.g. Alt+Tab) before the key-up event fires.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clear the entire framebuffer pixel buffer on resize instead of
preserving stale data from the previous resolution. Vec::resize()
only zeroes newly-added bytes, so old pixels were reinterpreted
with the new stride, producing garbled output after mode changes.
Fix bottom/right clipping by giving the Image explicit dimensions
bound to framebuffer size properties instead of using image-fit:
contain with a hardcoded toolbar width estimate. The window's
preferred size now derives from the layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Final review pass cross-referencing server RE with client protocol
spec and client RE. Key corrections and findings:
- Type 0x07 is MouseSync/ReSync, NOT ClientCutText — dispatches
through DeviceManager to MouseDevice::ReSync ioctl
- Differential frame tile format includes 4 bytes padding
(uninitialized stack data from CopyTileData)
- Differential-to-full fallback when diff data exceeds frame size
- Hermon sub-header byte 1 is color depth flag (0=RGB555, else 8bpp)
- ServerInit firmware bug: width/height are sent in reversed order
- Type 0x35 firmware bug: server sends 3 bytes but client expects 6
(missing mouse info bytes)
- KeepAlive broadcast dispatches as type 0x39 PrivilegeInfo with
hi=7 for LED sync
- libutility.so function signatures: UtilAuthUser returns 0-9 on
success (>=10 failure), UtilGetNowPowerStatus returns u8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the ProtocolHandler dispatch loop and build comprehensive
message type reference tables. Key findings:
- ProtocolHandler: 24 switch cases, flow is ProcessCommandQueue ->
read type -> PermissionFilter -> dispatch/skip. Type 0x16
uniquely triggers two handlers sequentially
- SetEncoding handlers: type 0x08/0x36 set mouse mode, type 0x34
is a no-op stub
- RequestRefresh (0x3a): triggers USB mouse hot-plug, not video
- Complete client-to-server table: 20 message types with payload
formats, sizes, and permission requirements
- Complete server-to-client table: 9 response types with triggers
- Byte-level wire format for all 9 server responses including
FramebufferUpdate 24-byte header, CursorPos, KeepAlive, VideoInfo,
KbdMouseInfo, SessionInfo, PrivilegeCommand, ViewerLang, SessionStatus
- PowerControl: full 4-state dispatch (off/on/reset/soft-off)
- SetViewerLang: persists to /nv/IKVMViewerLang via atomic write
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the complete input path from client events to USB HID
device writes. Key findings:
- KeyEvent (type 0x04): 17-byte payload with AES encryption flag,
decrypts to [down_flag, keycode], writes 8-byte record to
/dev/keyboard. down_flag=2 triggers press+release sequence
- PointerEvent (type 0x05): same encryption scheme, decrypts to
[button_mask, x, y], writes 20-byte record to /dev/mouse with
display dimensions for coordinate scaling
- usb_hid.ko (unstripped, "ATEN, Bobby"): two virtual USB HID
devices with EP1 (keyboard, 8-byte boot protocol reports) and
EP2 (mouse, 3-6 byte reports with 4 modes: absolute/relative/
scroll/passthrough). 5 ioctls for hotplug, mouse mode, resync, LEDs
- AES encryption: single-block CBC with static key/IV, first byte
of payload is encryption flag (0=plaintext, non-zero=encrypted)
- KeyboardDevice and MouseDevice object layouts and vtables
- DeviceManager vtable corrections and delegate target mappings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the complete authentication flow, session lifecycle,
message queue IPC, and permission system. Key findings:
- Authentication: VNC type 0x10, ATEN-modified challenge/response
with plaintext username/password, web SSO via /tmp/sess_* files,
fallback to IPMI UtilAuthUser
- ServerInit: standard RFB fields + ATEN extension with session_id
and 4 permission bytes mapped from IPMI privilege levels
- Session lifecycle: accept loop, per-session thread with Stream/
RFBProtocol construction, max session enforcement, peer notification
- POSIX message queues: /<thread_id_hex>, 0x104-byte messages with
7 known command codes for inter-session communication
- Permission filter: message type to permission byte mapping,
GetFilterLen payload size table for all 20 message types
- SessionContext (0x50 bytes) and PrivilegeInfo (0x164 bytes) layouts
- 25 new functions mapped, 12 existing entries updated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the complete video capture flow from FBUpdateRequest to
frame response. Key findings:
- DeviceManager object (global at 0x1e560) with VideoCaptureDevice,
KeyboardDevice, and MouseDevice sub-objects
- DeviceManager vtable (0x14518) with 18 virtual methods
- VideoCaptureDevice (0x84 bytes) manages /dev/vcd and mmap'd buffers
- WPCM450 VCD hardware register map and 4-slot frame buffer layout
- Hermon encoding: full frame (0x01 + magic + raw pixels) vs
differential (0x00 + tile count + 16x16 dirty tiles)
- Tile dirty bitmap at 0xF0020000 for differential encoding
- Preview thread and snapshot mechanisms
- VideoControl handlers (all three delegate to VCD::VideoControl)
- 50+ new functions identified and mapped
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ATEN BMC expects USB HID keycodes in the key event packet, not X11
keysyms. Sending keysyms caused wrong keys (e.g. Q→Down Arrow, C→F10)
because the BMC interpreted the keysym value as a HID keycode.
Rewrote keymap to use HID keycodes from Java KeyMap.initHidKeyMap(),
renamed keysym→keycode throughout, and added toolbar width compensation
to window sizing so the framebuffer image gets its full width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hermon incremental tiles have a 6-byte header (4 reserved + tile_y at
offset 4 + tile_x at offset 5), not 2 bytes. Confirmed via Ghidra
decompilation of HermonVideoDecoder::Decode. The 2-byte header caused
every tile after the first to misalign by 4 bytes, producing square
artifacts and preventing framebuffer updates.
Keyboard keysyms now use uppercase letters (0x41-0x5A) and shifted
symbol variants to match the original Java client's processVK Table 1,
which the BMC firmware's keysym-to-HID translation table expects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instrument the message loop, hermon decoder, and writer thread with
log crate calls to help diagnose framebuffer update and keyboard issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The 5ms read timeout (added for keyboard input polling) caused
read_exact calls inside message handlers to fail with EAGAIN when
large framebuffer updates didn't arrive within the window. This
crashed the session 15-30 seconds after any keyboard input.
Split the socket with try_clone: a dedicated writer thread handles
keyboard events via blocking recv, while the reader uses a 1-second
timeout (only for stop-flag checking). This fixes both the crash and
the non-updating framebuffer (content updates from the server can now
survive long enough to be decoded and displayed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
xkbcommon-dl loads libxkbcommon-x11.so via dlopen at runtime, which
isn't covered by the binary's RPATH in nix builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Physical key passthrough approach: capture winit PhysicalKey codes,
map to X11 keysyms via fixed table, send as independent key events.
Avoids local keymap dependency entirely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The BMC's GetDecoder is a singleton factory that creates a decoder on
the first frame and reuses it for all subsequent frames. The BMC sends
encoding 0x00 for incremental frames after the initial 0x59 (Hermon)
frame, which was incorrectly rejected as unsupported.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use ToSocketAddrs instead of parse::<SocketAddr> so hostnames resolve
- Update README.md to reflect aten-gui is now a KVM console viewer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>