diff --git a/qemu-options.hx b/qemu-options.hx index 1698a0c751..05fe35ceb6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2222,6 +2222,10 @@ SRST transmission. When not using an -audiodev argument, this option must be omitted, otherwise is must be present and specify a valid audiodev. + + ``power-control`` + Permit the remote client to issue shutdown, reboot or reset power + control requests. ERST ARCHHEADING(, QEMU_ARCH_I386) diff --git a/ui/vnc.c b/ui/vnc.c index 69e92b1ef3..a0bf750767 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -30,6 +30,7 @@ #include "trace.h" #include "hw/qdev-core.h" #include "sysemu/sysemu.h" +#include "sysemu/runstate.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" @@ -2042,6 +2043,17 @@ static void send_ext_audio_ack(VncState *vs) vnc_flush(vs); } +static void send_xvp_message(VncState *vs, int code) +{ + vnc_lock_output(vs); + vnc_write_u8(vs, VNC_MSG_SERVER_XVP); + vnc_write_u8(vs, 0); /* pad */ + vnc_write_u8(vs, 1); /* version */ + vnc_write_u8(vs, code); + vnc_unlock_output(vs); + vnc_flush(vs); +} + static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) { int i; @@ -2121,6 +2133,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) case VNC_ENCODING_LED_STATE: vs->features |= VNC_FEATURE_LED_STATE_MASK; break; + case VNC_ENCODING_XVP: + if (vs->vd->power_control) { + vs->features |= VNC_FEATURE_XVP; + send_xvp_message(vs, VNC_XVP_CODE_INIT); + } + break; case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9: vs->tight->compression = (enc & 0x0F); break; @@ -2353,6 +2371,42 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) client_cut_text(vs, read_u32(data, 4), data + 8); break; + case VNC_MSG_CLIENT_XVP: + if (!(vs->features & VNC_FEATURE_XVP)) { + error_report("vnc: xvp client message while disabled"); + vnc_client_error(vs); + break; + } + if (len == 1) { + return 4; + } + if (len == 4) { + uint8_t version = read_u8(data, 2); + uint8_t action = read_u8(data, 3); + + if (version != 1) { + error_report("vnc: xvp client message version %d != 1", + version); + vnc_client_error(vs); + break; + } + + switch (action) { + case VNC_XVP_ACTION_SHUTDOWN: + qemu_system_powerdown_request(); + break; + case VNC_XVP_ACTION_REBOOT: + send_xvp_message(vs, VNC_XVP_CODE_FAIL); + break; + case VNC_XVP_ACTION_RESET: + qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); + break; + default: + send_xvp_message(vs, VNC_XVP_CODE_FAIL); + break; + } + } + break; case VNC_MSG_CLIENT_QEMU: if (len == 1) return 2; @@ -3379,6 +3433,9 @@ static QemuOptsList qemu_vnc_opts = { },{ .name = "audiodev", .type = QEMU_OPT_STRING, + },{ + .name = "power-control", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, @@ -3942,6 +3999,8 @@ void vnc_display_open(const char *id, Error **errp) vd->non_adaptive = true; } + vd->power_control = qemu_opt_get_bool(opts, "power-control", false); + if (tlsauthz) { vd->tlsauthzid = g_strdup(tlsauthz); } else if (acl) { diff --git a/ui/vnc.h b/ui/vnc.h index c8d3ad9ec4..5feeef9df0 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -176,6 +176,7 @@ struct VncDisplay int ws_subauth; /* Used by websockets */ bool lossy; bool non_adaptive; + bool power_control; QCryptoTLSCreds *tlscreds; QAuthZ *tlsauthz; char *tlsauthzid; @@ -412,6 +413,7 @@ enum { #define VNC_ENCODING_TIGHT_PNG 0xFFFFFEFC /* -260 */ #define VNC_ENCODING_LED_STATE 0XFFFFFEFB /* -261 */ #define VNC_ENCODING_DESKTOP_RESIZE_EXT 0XFFFFFECC /* -308 */ +#define VNC_ENCODING_XVP 0XFFFFFECB /* -309 */ #define VNC_ENCODING_ALPHA_CURSOR 0XFFFFFEC6 /* -314 */ #define VNC_ENCODING_WMVi 0x574D5669 @@ -453,6 +455,7 @@ enum VncFeatures { VNC_FEATURE_ZRLE, VNC_FEATURE_ZYWRLE, VNC_FEATURE_LED_STATE, + VNC_FEATURE_XVP, }; #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE) @@ -467,6 +470,7 @@ enum VncFeatures { #define VNC_FEATURE_ZRLE_MASK (1 << VNC_FEATURE_ZRLE) #define VNC_FEATURE_ZYWRLE_MASK (1 << VNC_FEATURE_ZYWRLE) #define VNC_FEATURE_LED_STATE_MASK (1 << VNC_FEATURE_LED_STATE) +#define VNC_FEATURE_XVP_MASK (1 << VNC_FEATURE_XVP) /* Client -> Server message IDs */ @@ -519,6 +523,15 @@ enum VncFeatures { #define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN 1 #define VNC_MSG_SERVER_QEMU_AUDIO_DATA 2 +/* XVP server -> client status code */ +#define VNC_XVP_CODE_FAIL 0 +#define VNC_XVP_CODE_INIT 1 + +/* XVP client -> server action request */ +#define VNC_XVP_ACTION_SHUTDOWN 2 +#define VNC_XVP_ACTION_REBOOT 3 +#define VNC_XVP_ACTION_RESET 4 + /***************************************************************************** *