
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//

/*++

Module Name:

    lxinitshared.h

Abstract:

    This is the header file for definitions shared between Windows and init.

--*/

#pragma once

#include <stdint.h>
#include <type_traits>
#include "prettyprintshared.h"

#if defined(_MSC_VER)

#pragma warning(disable : 4200) // Zero-sized array

#endif

//
// The path of the init daemon.
//

#define LX_INIT_PATH "/init"

//
// Command line argument for sending import result message.
//

#define LX_INIT_IMPORT_MESSAGE_ARG "--import-result-message"

//
// The name of the server.
//

#define LX_INIT_SERVER_NAME "wslservice"

//
// Max size for a distribution name.
//

#define LX_INIT_DISTRO_NAME_MAX 256

//
// The header for autogenerated files.
//

#define LX_INIT_AUTO_GENERATED_FILE_HEADER \
    "# This file was automatically generated by WSL. To stop automatic " \
    "generation of this file, add the following entry to /etc/wsl.conf:\n"

//
// The second header for resolv.conf.
//

#define LX_INIT_RESOLVCONF_PREFIX "# [network]\n# generateResolvConf = false\n"

//
// The destination prefix for the default routing rule.
//

#define LX_INIT_UNSPECIFIED_ADDRESS L"0.0.0.0"
#define LX_INIT_UNSPECIFIED_V6_ADDRESS L"::"

#define LX_INIT_DEFAULT_ROUTE_PREFIX LX_INIT_UNSPECIFIED_ADDRESS "/0"
#define LX_INIT_DEFAULT_ROUTE_V6_PREFIX LX_INIT_UNSPECIFIED_V6_ADDRESS "/0"

//
// The hard-coded link-local addresses used for communicating over the loopback to the host
//
#define LX_INIT_IPV4_LOOPBACK_GATEWAY_ADDRESS "169.254.73.152"
#define LX_INIT_IPV6_LOOPBACK_GATEWAY_ADDRESS "fe80::500:4aef:feef:2aa2"

//
// Linux device name for the GELNIC used for loopback communication in mirrored networking mode.
//
#define LX_INIT_LOOPBACK_DEVICE_NAME "loopback0"

//
// Default IP address used by the DNS tunneling listener.
// N.B. As of Germanium release, HNS will never assign a subnet from the 10.0.0.0/8 range to the WSL NAT network, so there
// can't be a conflict between that range and the default IP 10.255.255.254.
//
#define LX_INIT_DNS_TUNNELING_IP_ADDRESS "10.255.255.254"

//
// The data for launching a new process. The structure is variable size with the
// strings starting at the Buffer member in the following order: Filename,
// CurrentWorkingDirectory, CommandLine, and finally Environment.
//

#define LX_INIT_CREATE_PROCESS_USE_CONSOLE (LXBUS_IPC_HANDLE_ID_INVALID)

#define LX_INIT_STD_FD_COUNT 3

#define LX_INIT_USER_NOT_FOUND 67
#define LX_INIT_TTY_LIMIT 87

#define LX_INIT_CREATE_NT_PROCESS_SOCKETS 4

//
// HvSocket ports used for WSL VM Mode.
//

#define LX_INIT_UTILITY_VM_INIT_PORT (50000)
#define LX_INIT_UTILITY_VM_PLAN9_PORT (50001)
#define LX_INIT_UTILITY_VM_PLAN9_DRVFS_PORT (50002)
#define LX_INIT_UTILITY_VM_PLAN9_DRVFS_ADMIN_PORT (50003)
#define LX_INIT_UTILITY_VM_VIRTIOFS_PORT (50004)
#define LX_INIT_UTILITY_VM_CRASH_DUMP_PORT (50005)

//
// HvSocket buffer size for 9p connections.
//
// N.B. The kernel doubles this value.
//

#define LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE (65536)

//
// Default buffer size for relaying.
//

#define LX_RELAY_BUFFER_SIZE 0x1000

//
// HVC terminal devices.
//

#define LX_INIT_HVC_DEBUG_SHELL "hvc2"
#define LX_INIT_HVC_TELEMETRY "hvc1"

// Since -1 is used to indicate "any port", it can't be an actual port number and is used as an
// invalid value.
// N.B. Can't use the actual VMADDR_PORT_ANY constant since the header isn't available.
#define LX_INIT_UTILITY_VM_INVALID_PORT (UINT_MAX)

#define LX_INIT_UTILITY_VM_INIT_SOCKET_FD (100)

#define LX_INIT_UTILITY_VM_DRVFS_SHARE_NAME "drvfs"

#define LX_INIT_DRVFS_VIRTIO_TAG "drvfs"
#define LX_INIT_DRVFS_ADMIN_VIRTIO_TAG "drvfsa"

//
// Typical default DrvFs-specific 9p mount options.
//
// N.B. These are used to prepopulate virtiofs shares with default mount options.
//      These will match the default values used by the system distro, and will typically
//      match the default uid / gid for the user distro. If the values do not match, a new
//      virtiofs share will be created.
//

#define LX_INIT_DEFAULT_PLAN9_MOUNT_OPTIONS ";uid=1000;gid=1000;symlinkroot=/mnt/"

#define LX_INIT_UTILITY_VM_CREATE_PROCESS_SOCKET_COUNT (5)

#define LX_INIT_NO_CONSOLE (LXBUS_IPC_CONSOLE_ID_INVALID)

#define LX_INIT_CREATE_PROCESS_RESULT_FLAG_GUI_APPLICATION 0x1

//
// The timeout for hvsocket connect().
//

#define LX_INIT_HVSOCKET_TIMEOUT_SECONDS (30)

//
// The data for beginning a port listener.
//

#define LX_INIT_LOCALHOST_RELAY "localhost"

//
// Environment variable to determine if root init logic, or WSL entrypoint should be used.
//

#define WSL_ROOT_INIT_ENV "WSL_ROOT_INIT"

#define WSL_SOCKET_LOG_ENV "WSL_SOCKET_LOG"

#define WSL_ENABLE_CRASH_DUMP_ENV "WSL_ENABLE_CRASH_DUMP"

#define WSL_DEBUG_ENV "WSL_DEBUG"

#define WSL_DISTRIBUTION_CONF "/etc/wsl-distribution.conf"

//
// Defines needed for GUI support.
//

#define PULSE_SERVER_ENV "PULSE_SERVER"
#define PULSE_SERVER_NAME "PulseServer"
#define WAYLAND_DISPLAY_ENV "WAYLAND_DISPLAY"
#define WAYLAND_DISPLAY_VALUE "wayland-0"
#define WAYLAND_RUNTIME_DIR "runtime-dir"
#define X11_DISPLAY_ENV "DISPLAY"
#define X11_DISPLAY_VALUE ":0"
#define X11_SOCKET_NAME ".X11-unix"
#define XDG_RUNTIME_DIR_ENV "XDG_RUNTIME_DIR"

//
// GNS arguments
//

#define LX_INIT_GNS "gns"
#define LX_INIT_GNS_ADAPTER_ARG "--adapter"
#define LX_INIT_GNS_SOCKET_ARG "--socket"
#define LX_INIT_GNS_DNS_SOCKET_ARG "--dns_socket"
#define LX_INIT_GNS_DNS_TUNNELING_IP "--dns_tunneling_ip"
#define LX_INIT_GNS_MESSAGE_TYPE_ARG "--msg_type"

//
// Plan9 arguments
//

#define LX_INIT_PLAN9 "plan9"
#define LX_INIT_PLAN9_CONTROL_SOCKET_ARG "--control-socket"
#define LX_INIT_PLAN9_SOCKET_PATH_ARG "--socket-path"
#define LX_INIT_PLAN9_SERVER_FD_ARG "--server-fd"
#define LX_INIT_PLAN9_LOG_FILE_ARG "--log-file"
#define LX_INIT_PLAN9_LOG_LEVEL_ARG "--log-level"
#define LX_INIT_PLAN9_PIPE_FD_ARG "--pipe-fd"
#define LX_INIT_PLAN9_TRUNCATE_LOG_ARG "--log-truncate"

//
// wsl-capture-crash
//

#define LX_INIT_WSL_CAPTURE_CRASH "wsl-capture-crash"

#define LX_INIT_WSL_GENERATOR "wsl-generator"

#define LX_INIT_WSL_USER_GENERATOR "wsl-user-generator"

//
// WSL2-specific environment variables.
//

#define LX_WSL2_CROSS_DISTRO_ENV "WSL2_CROSS_DISTRO"
#define LX_WSL2_DISTRO_NAME_ENV "WSL2_DISTRO_NAME"
#define LX_WSL2_GUI_APP_SUPPORT_ENV "WSL2_GUI_APPS_ENABLED"
#define LX_WSL2_KERNEL_MODULES_MOUNT_ENV "WSL2_KERNEL_MODULES_MOUNT"
#define LX_WSL2_KERNEL_MODULES_PATH_ENV "WSL2_KERNEL_MODULES_PATH"
#define LX_WSL2_SYSTEM_DISTRO_SHARE_ENV "WSL2_SYSTEM_DISTRO_SHARE"
#define LX_WSL2_GPU_SHARE_ENV "WSL2_GPU_SHARE_ENV_"
#define LX_WSL2_SHARED_MEMORY_OB_DIRECTORY "WSL2_SHARED_MEMORY_OB_DIRECTORY"
#define LX_WSL2_INSTALL_PATH "WSL2_INSTALL_PATH"
#define LX_WSL2_SAFE_MODE "WSL2_SAFE_MODE"
#define LX_WSL2_USER_PROFILE "WSL2_USER_PROFILE"
#define LX_WSL2_VM_ID_ENV "WSL2_VM_ID"
#define LX_WSL_PID_ENV "WSL2_PID"
#define LX_INIT_TELEMETRY_AGENT "telagent"
#define LX_WSL2_DISTRO_READ_ONLY_ENV "WSL_DISTRO_READ_ONLY"
#define LX_WSL2_NETWORKING_MODE_ENV "WSL2_NETWORKING_MODE"
#define LX_WSL2_DISTRO_INIT_PID "WSL2_DISTRO_INIT_PID"

//
// Command line arguments shared between init & mini_init
//

#define INIT_PORT_TRACKER_FD_ARG "--port-tracker-fd"
#define INIT_BPF_FD_ARG "--bpf-fd"
#define INIT_NETLINK_FD_ARG "--netlink-fd"
#define INIT_PORT_TRACKER_LOCALHOST_RELAY "--localhost-relay"

//
// The types of messages that can be sent to init and mini init.
//

typedef enum _LX_MESSAGE_TYPE
{
    LxMiniInitMessageAny = 0,
    LxInitMessageCreateProcess,
    LxInitMessageCreateSession,
    LxInitMessageCreateSessionResponse,
    LxInitMessageNetworkInformation,
    LxInitMessageInitialize,
    LxInitMessageInitializeResponse,
    LxInitMessageTimezoneInformation,
    LxInitMessageCreateProcessUtilityVm,
    LxInitMessageExitStatus,
    LxInitMessageWindowSizeChanged,
    LxInitMessageCreateProcessResponse,
    LxInitMessageQueryDrvfsElevated,
    LxInitMessageRemountDrvfs,
    LxInitMessageTerminateInstance,
    LxInitMessageStartSocketRelay,
    LxInitMessageQueryEnvironmentVariable,
    LxInitMessageQueryFeatureFlags,
    LxInitMessageKernelVersion,
    LxInitMessageAddVirtioFsDevice,
    LxInitMessageAddVirtioFsDeviceResponse,
    LxInitMessageRemountVirtioFsDevice,
    LxInitMessageStartDistroInit,
    LxInitMessageCreateLoginSession,
    LxInitMessageStopPlan9Server,
    LxInitMessageQueryNetworkingMode,
    LxInitMessageQueryVmId,
    LxInitCreateProcess,
    LxInitOobeResult,
    LxMiniInitMessageLaunchInit,
    LxMiniInitMessageImport,
    LxMiniInitMessageImportInplace,
    LxMiniInitMessageExport,
    LxMiniInitMessageCreateInstanceResult,
    LxMiniInitMessageImportResult,
    LxMiniInitMessageEjectVhd,
    LxMiniInitMessageEarlyConfig,
    LxMiniInitMessageInitialConfig,
    LxMiniInitMessageMount,
    LxMiniInitMessageUnmount,
    LxMiniInitMessageDetach,
    LxMiniInitMessageMountStatus,
    LxMiniInitMessageNetworkInfo,
    LxMiniInitMessageGuestCapabilities,
    LxMiniInitMessageWaitForPmemDevice,
    LxMiniInitMessageChildExit,
    LxMiniInitMountFolder,
    LxMiniInitCreateInstancePid,
    LxMiniInitTelemetryMessage,
    LxMinitWaitForPmemDeviceResult,
    LxMiniInitMessageResizeDistribution,
    LxMiniInitMessageResizeDistributionResponse,
    LxProcessCrash,
    LxGnsMessageInterfaceConfiguration,
    LxGnsMessageResult,
    LxGnsMessageNotification,
    LxGnsMessagePortMappingRequest,
    LxGnsMessagePortMappingResponse,
    LxGnsMessageSetPortListener,
    LxGnsMessagePortListenerRelayStart,
    LxGnsMessagePortListenerRelayStop,
    LxGnsMessageVmNicCreatedNotification,
    LxGnsMessageCreateDeviceRequest,
    LxGnsMessageModifyGuestDeviceSettingRequest,
    LxGnsMessageLoopbackRoutesRequest,
    LxGnsMessageDeviceSettingRequest,
    LxGnsMessageIfStateChangeRequest,
    LxGnsMessageIfStateChangeResponse,
    LxGnsMessageInitialIpConfigurationNotification,
    LxGnsMessageSetupIpv6,
    LxGnsMessageDnsTunneling,
    LxGnsMessageNoOp,
    LxGnsMessageGlobalNetFilter,
    LxGnsMessageInterfaceNetFilter,
    LxGnsMessageConnectTestRequest,
    LxGnsMessageListenerRelay,
    LxMessageResultBool,
    LxMessageResultInt32,
    LxMessageResultUint32,
    LxMessageResultUint8
} LX_MESSAGE_TYPE,
    *PLX_MESSAGE_TYPE;

inline auto ToString(LX_MESSAGE_TYPE messageType)
{
#define X(Value) \
    case Value: \
        return #Value;

    switch (messageType)
    {
        X(LxMiniInitMessageAny)
        X(LxInitMessageCreateProcess)
        X(LxInitMessageCreateSession)
        X(LxInitMessageCreateSessionResponse)
        X(LxInitMessageNetworkInformation)
        X(LxInitMessageInitialize)
        X(LxInitMessageInitializeResponse)
        X(LxInitMessageTimezoneInformation)
        X(LxInitMessageCreateProcessUtilityVm)
        X(LxInitMessageExitStatus)
        X(LxInitMessageWindowSizeChanged)
        X(LxInitMessageCreateProcessResponse)
        X(LxInitMessageQueryDrvfsElevated)
        X(LxInitMessageRemountDrvfs)
        X(LxInitMessageTerminateInstance)
        X(LxInitMessageStartSocketRelay)
        X(LxInitMessageQueryEnvironmentVariable)
        X(LxInitMessageQueryFeatureFlags)
        X(LxInitMessageKernelVersion)
        X(LxInitMessageAddVirtioFsDevice)
        X(LxInitMessageAddVirtioFsDeviceResponse)
        X(LxInitMessageRemountVirtioFsDevice)
        X(LxInitMessageStartDistroInit)
        X(LxInitMessageCreateLoginSession)
        X(LxInitMessageStopPlan9Server)
        X(LxInitMessageQueryNetworkingMode)
        X(LxInitCreateProcess)
        X(LxInitOobeResult)
        X(LxMiniInitMessageLaunchInit)
        X(LxMiniInitMessageImport)
        X(LxMiniInitMessageExport)
        X(LxMiniInitMessageCreateInstanceResult)
        X(LxMiniInitMessageImportResult)
        X(LxMiniInitMessageEjectVhd)
        X(LxMiniInitMessageEarlyConfig)
        X(LxMiniInitMessageInitialConfig)
        X(LxMiniInitMessageMount)
        X(LxMiniInitMessageUnmount)
        X(LxMiniInitMessageDetach)
        X(LxMiniInitMessageMountStatus)
        X(LxMiniInitMessageNetworkInfo)
        X(LxMiniInitMessageGuestCapabilities)
        X(LxMiniInitMessageWaitForPmemDevice)
        X(LxMiniInitMessageChildExit)
        X(LxMiniInitMessageResizeDistribution)
        X(LxMiniInitMessageResizeDistributionResponse)
        X(LxMiniInitMountFolder)
        X(LxMiniInitCreateInstancePid)
        X(LxMinitWaitForPmemDeviceResult)
        X(LxProcessCrash)
        X(LxGnsMessageInterfaceConfiguration)
        X(LxGnsMessageResult)
        X(LxGnsMessageNotification)
        X(LxGnsMessagePortMappingRequest)
        X(LxGnsMessagePortMappingResponse)
        X(LxGnsMessageSetPortListener)
        X(LxGnsMessagePortListenerRelayStart)
        X(LxGnsMessagePortListenerRelayStop)
        X(LxGnsMessageVmNicCreatedNotification)
        X(LxGnsMessageCreateDeviceRequest)
        X(LxGnsMessageModifyGuestDeviceSettingRequest)
        X(LxGnsMessageLoopbackRoutesRequest)
        X(LxGnsMessageDeviceSettingRequest)
        X(LxGnsMessageIfStateChangeRequest)
        X(LxGnsMessageIfStateChangeResponse)
        X(LxGnsMessageInitialIpConfigurationNotification)
        X(LxGnsMessageSetupIpv6)
        X(LxGnsMessageDnsTunneling)
        X(LxGnsMessageNoOp)
        X(LxGnsMessageGlobalNetFilter)
        X(LxGnsMessageInterfaceNetFilter)
        X(LxGnsMessageConnectTestRequest)
        X(LxMessageResultBool)
        X(LxMessageResultInt32)
        X(LxMessageResultUint32)
        X(LxMiniInitTelemetryMessage)
        X(LxMessageResultUint8)

    default:
        return "<unexpected LX_MESSAGE_TYPE>";
    }

#undef X
}

typedef enum _LX_INIT_DRVFS_MOUNT
{
    LxInitDrvfsMountNone = 0,
    LxInitDrvfsMountNonElevated,
    LxInitDrvfsMountElevated
} LX_INIT_DRVFS_MOUNT,
    *PLX_INIT_DRVFS_MOUNT;

#define CONCAT_IMPL(A, B) L##A##B

#define CONCAT(A, B) CONCAT_IMPL(A, B)

#define LX_INIT_RESOLVCONF_FULL_HEADER CONCAT(LX_INIT_AUTO_GENERATED_FILE_HEADER, LX_INIT_RESOLVCONF_PREFIX)

inline void PrettyPrint(std::stringstream& Out, LX_MESSAGE_TYPE Value)
{
    Out << ToString(Value);
}

enum class TRANSACTION_STEP : unsigned int
{
    NONE = 0,
    REQUEST = 1,
    FIRST_REPLY = 2,
};

struct MESSAGE_HEADER
{
    static inline auto Type = LxMiniInitMessageAny; // Setting this allows using MESSAGE_HEADER to receive any type of message

    LX_MESSAGE_TYPE MessageType;
    unsigned int MessageSize;
    unsigned int TransactionId;
    unsigned int TransactionStep;

    PRETTY_PRINT(FIELD(MessageType), FIELD(MessageSize), FIELD(TransactionId), FIELD(TransactionStep));
};

//
// The data for launching a new session.
//

typedef struct _LX_INIT_CREATE_SESSION_RESPONSE
{
    static inline auto Type = LxInitMessageCreateSessionResponse;

    MESSAGE_HEADER Header;
    unsigned int Port;

    PRETTY_PRINT(FIELD(Header), FIELD(Port));

} LX_INIT_CREATE_SESSION_RESPONSE, *PLX_INIT_CREATE_SESSION_RESPONSE;

typedef struct _LX_INIT_CREATE_SESSION
{
    static inline auto Type = LxInitMessageCreateSession;
    using TResponse = LX_INIT_CREATE_SESSION_RESPONSE;

    MESSAGE_HEADER Header;
    int64_t ConsoleId;

    PRETTY_PRINT(FIELD(Header), FIELD(ConsoleId));
} LX_INIT_CREATE_SESSION, *PLX_INIT_CREATE_SESSION;

typedef enum _CREATE_PROCESS_SHELL_OPTIONS
{
    ShellOptionsLogin = 0x1
} CREATE_PROCESS_SHELL_OPTIONS,
    *PCREATE_PROCESS_SHELL_OPTIONS;

//
// N.B. The common create process structure must be the last element in the
//      containing struct because it contains an anysize array.
//

template <typename T>
constexpr LX_MESSAGE_TYPE GetResultMessageType()
{
    if constexpr (std::is_same_v<T, bool>)
    {
        return LxMessageResultBool;
    }
    else if constexpr (std::is_same_v<T, int32_t>)
    {
        return LxMessageResultInt32;
    }
    else if constexpr (std::is_same_v<T, uint32_t>)
    {
        return LxMessageResultUint32;
    }
    else if constexpr (std::is_same_v<T, uint8_t>)
    {
        return LxMessageResultUint8;
    }
    else
    {
        static_assert(sizeof(T) != sizeof(T));
    }
}

template <typename T>
struct RESULT_MESSAGE
{
    static inline auto Type = GetResultMessageType<T>();

    MESSAGE_HEADER Header;
    T Result;

    PRETTY_PRINT(FIELD(Header), FIELD(Result));
};

typedef struct _LX_PROCESS_CRASH
{
    static inline auto Type = LxProcessCrash;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    std::uint64_t Timestamp;
    std::uint32_t Signal;
    std::uint64_t Pid;

    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Timestamp), FIELD(Signal), FIELD(Pid), BUFFER_FIELD(Buffer));

} LX_PROCESS_CRASH, *PLX_PROCESS_CRASH;

typedef struct _LX_INIT_CREATE_PROCESS_COMMON
{
    unsigned int FilenameOffset;
    unsigned int CurrentWorkingDirectoryOffset;
    unsigned int CommandLineOffset;
    unsigned short CommandLineCount;
    unsigned int EnvironmentOffset;
    unsigned short EnvironmentCount;
    unsigned int NtEnvironmentOffset;
    unsigned short NtEnvironmentCount;
    unsigned int NtPathOffset;
    unsigned int ShellOptions;
    unsigned int UsernameOffset;
    unsigned int DefaultUid;
    int Flags;
    char Buffer[];
} LX_INIT_CREATE_PROCESS_COMMON, *PLX_INIT_CREATE_PROCESS_COMMON;

typedef struct _LX_INIT_CREATE_PROCESS_RESPONSE
{
    static inline auto Type = LxInitMessageCreateProcessResponse;

    MESSAGE_HEADER Header;
    int Result;
    int64_t SignalPipeId;
    unsigned int Flags;

    PRETTY_PRINT(FIELD(Header), FIELD(Result), FIELD(SignalPipeId), FIELD(Flags));
} LX_INIT_CREATE_PROCESS_RESPONSE, *PLX_INIT_CREATE_PROCESS_RESPONSE;

typedef struct _LX_INIT_CREATE_PROCESS
{
    static inline auto Type = LxInitMessageCreateProcess;
    using TResponse = _LX_INIT_CREATE_PROCESS_RESPONSE;

    MESSAGE_HEADER Header;
    int64_t IpcServerId;
    int64_t StdFdIds[LX_INIT_STD_FD_COUNT];
    int64_t ForkTokenId;
    LX_INIT_CREATE_PROCESS_COMMON Common;

    PRETTY_PRINT(FIELD(Header), FIELD(IpcServerId), FIELD(StdFdIds), FIELD(ForkTokenId));
} LX_INIT_CREATE_PROCESS, *PLX_INIT_CREATE_PROCESS;

typedef struct _LX_INIT_CREATE_NT_PROCESS_COMMON
{
    int64_t StdFdIds[LX_INIT_STD_FD_COUNT];
    unsigned int FilenameOffset;
    unsigned int CurrentWorkingDirectoryOffset;
    unsigned int CommandLineOffset;
    unsigned short CommandLineCount;
    unsigned int EnvironmentOffset;
    unsigned short Rows;
    unsigned short Columns;
    bool CreatePseudoconsole;
    char Buffer[];

    // Not pretty-printing command line and env since it could contain PII.
    PRETTY_PRINT(FIELD(StdFdIds), STRING_FIELD(FilenameOffset), STRING_FIELD(CurrentWorkingDirectoryOffset), FIELD(Rows), FIELD(Columns), FIELD(CreatePseudoconsole));
} LX_INIT_CREATE_NT_PROCESS_COMMON, *PLX_INIT_CREATE_NT_PROCESS_COMMON;

using PCLX_INIT_CREATE_NT_PROCESS_COMMON = const LX_INIT_CREATE_NT_PROCESS_COMMON*;

typedef struct _LX_INIT_CREATE_NT_PROCESS
{
    static inline auto Type = LxInitMessageCreateProcess;

    MESSAGE_HEADER Header;
    int64_t StdFdIds[LX_INIT_STD_FD_COUNT];
    LX_INIT_CREATE_NT_PROCESS_COMMON Common;

    PRETTY_PRINT(FIELD(Header), FIELD(StdFdIds), FIELD(Common));

} LX_INIT_CREATE_NT_PROCESS, *PLX_INIT_CREATE_NT_PROCESS;

using PCLX_INIT_CREATE_NT_PROCESS = const LX_INIT_CREATE_NT_PROCESS*;

typedef struct _LX_INIT_CREATE_NT_PROCESS_UTILITY_VM
{
    static inline auto Type = LxInitMessageCreateProcessUtilityVm;

    MESSAGE_HEADER Header;
    unsigned int Port;
    LX_INIT_CREATE_NT_PROCESS_COMMON Common;

    PRETTY_PRINT(FIELD(Header), FIELD(Port), FIELD(Common));
} LX_INIT_CREATE_NT_PROCESS_UTILITY_VM, *PLX_INIT_CREATE_NT_PROCESS_UTILITY_VM;

using PCLX_INIT_CREATE_NT_PROCESS_UTILITY_VM = const LX_INIT_CREATE_NT_PROCESS_UTILITY_VM*;

//
// The data communicating networking information. The structure is variable
// size and the FileContents member contains the string to write to the
// /etc/resolv.conf file.
//

typedef struct _LX_INIT_NETWORK_INFORMATION
{
    static inline auto Type = LxInitMessageNetworkInformation;

    MESSAGE_HEADER Header;
    unsigned int FileHeaderIndex;
    unsigned int FileContentsIndex;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), STRING_FIELD(FileHeaderIndex), STRING_FIELD(FileContentsIndex));
} LX_INIT_NETWORK_INFORMATION, *PLX_INIT_NETWORK_INFORMATION;

typedef struct _LX_INIT_CREATE_LOGIN_SESSION
{
    static inline auto Type = LxInitMessageCreateLoginSession;
    using TResponse = RESULT_MESSAGE<bool>;

    MESSAGE_HEADER Header;
    unsigned int Uid;
    unsigned int Gid;
    char Buffer[]; // Contains username

    PRETTY_PRINT(FIELD(Header), FIELD(Uid), FIELD(Gid), BUFFER_FIELD(Buffer));
} LX_INIT_CREATE_LOGIN_SESSION, *PLX_INIT_CREATE_LOGIN_SESSION;

//
// The buffer of the query environment variable struct contains the name of the variable
// to query for. On response, it will contain the value of the environment variable.
//

typedef struct _LX_INIT_QUERY_ENVIRONMENT_VARIABLE
{
    static inline auto Type = LxInitMessageQueryEnvironmentVariable;

    MESSAGE_HEADER Header;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
} LX_INIT_QUERY_ENVIRONMENT_VARIABLE, *PLX_INIT_QUERY_ENVIRONMENT_VARIABLE;

typedef struct _LX_GNS_RESULT
{
    static inline auto Type = LxGnsMessageResult;

    MESSAGE_HEADER Header;
    int Result;
    char Buffer[];

    // Note: 'Buffer' doesn't always contain a string, so don't pretty print it.
    PRETTY_PRINT(FIELD(Header), FIELD(Result));
} LX_GNS_RESULT, *PLX_GNS_RESULT;

typedef struct _LX_GNS_INTERFACE_CONFIGURATION
{
    static inline auto Type = LxGnsMessageInterfaceConfiguration;
    using TResponse = LX_GNS_RESULT;

    MESSAGE_HEADER Header;
    char Content[];

    PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Content));
} LX_GNS_INTERFACE_CONFIGURATION, *PLX_GNS_INTERFACE_CONFIGURATION;

typedef struct _LX_GNS_NOTIFICATION
{
    static inline auto Type = LxGnsMessageNotification;
    using TResponse = LX_GNS_RESULT;

    MESSAGE_HEADER Header;
    GUID AdapterId;
    char Content[];

    PRETTY_PRINT(FIELD(Header), FIELD(AdapterId), BUFFER_FIELD(Content));
} LX_GNS_NOTIFICATION, *PLX_GNS_NOTIFICATION;

typedef struct _LX_GNS_PORT_ALLOCATION_REQUEST
{
    static inline auto Type = LxGnsMessagePortMappingRequest;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    uint32_t Address32[4];
    uint16_t Port;
    int Af;
    int Protocol;
    bool Allocate;

    PRETTY_PRINT(FIELD(Header), FIELD(Address32), FIELD(Port), FIELD(Af), FIELD(Protocol), FIELD(Allocate));
} LX_GNS_PORT_ALLOCATION_REQUEST, *PLX_GNS_PORT_ALLOCATION_REQUEST;

typedef struct _LX_GNS_SET_PORT_LISTENER
{
    static inline auto Type = LxGnsMessageSetPortListener;

    MESSAGE_HEADER Header;
    int HvSocketPort;

    PRETTY_PRINT(FIELD(Header), FIELD(HvSocketPort));
} LX_GNS_SET_PORT_LISTENER, *PLX_GNS_SET_PORT_LISTENER;

static_assert(sizeof(LX_GNS_SET_PORT_LISTENER) == 20);

typedef struct _LX_GNS_PORT_LISTENER_RELAY
{
    static inline auto Type = LxGnsMessageListenerRelay;

    MESSAGE_HEADER Header;
    unsigned short Family;
    unsigned short Port;
    unsigned int Address[4];

    PRETTY_PRINT(FIELD(Header), FIELD(Family), FIELD(Port), FIELD(Address));
} LX_GNS_PORT_LISTENER_RELAY, *PLX_GNS_START_PORT_LISTENER_RELAY;

using PCLX_GNS_PORT_LISTENER_RELAY = const LX_GNS_PORT_LISTENER_RELAY*;

typedef struct _LX_GNS_TUN_BRIDGE_REQUEST
{
    static inline auto Type = LxGnsMessageIfStateChangeRequest;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    char InterfaceName[16];
    bool InterfaceUp;

    PRETTY_PRINT(FIELD(Header), FIELD(InterfaceName), FIELD(InterfaceUp));
} LX_GNS_TUN_BRIDGE_REQUEST, *PLX_GNS_TUN_BRIDGE_REQUEST;

typedef struct _LX_GNS_DNS_CLIENT_IDENTIFIER
{
    // Protocol used by the Linux DNS client. Can be TCP or UDP.
    uint8_t Protocol;
    // Unique id that identifies the Linux DNS client. Used by the DNS server on the Linux side to know to which
    // DNS client to send back a DNS response.
    uint32_t DnsClientId;

    _LX_GNS_DNS_CLIENT_IDENTIFIER() = default;
    ~_LX_GNS_DNS_CLIENT_IDENTIFIER() noexcept = default;

    _LX_GNS_DNS_CLIENT_IDENTIFIER(const _LX_GNS_DNS_CLIENT_IDENTIFIER&) = default;
    _LX_GNS_DNS_CLIENT_IDENTIFIER& operator=(const _LX_GNS_DNS_CLIENT_IDENTIFIER&) = default;
} LX_GNS_DNS_CLIENT_IDENTIFIER, *PLX_GNS_DNS_CLIENT_IDENTIFIER;

typedef struct _LX_GNS_DNS_TUNNELING_MESSAGE
{
    static inline auto Type = LxGnsMessageDnsTunneling;

    MESSAGE_HEADER Header;
    LX_GNS_DNS_CLIENT_IDENTIFIER DnsClientIdentifier;
    // Raw DNS request or response (variable length).
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(DnsClientIdentifier.Protocol), FIELD(DnsClientIdentifier.DnsClientId));
} LX_GNS_DNS_TUNNELING_MESSAGE, *PLX_GNS_DNS_TUNNELING_MESSAGE;

// Verify there is no padding in the LX_GNS_DNS_TUNNELING_MESSAGE structure before the variable length Buffer field.
static_assert(offsetof(LX_GNS_DNS_TUNNELING_MESSAGE, Buffer) == sizeof(MESSAGE_HEADER) + sizeof(LX_GNS_DNS_CLIENT_IDENTIFIER));

typedef struct _LX_GNS_JSON_MESSAGE
{
    static inline auto Type = LxMiniInitMessageAny;
    using TResponse = LX_GNS_RESULT;

    MESSAGE_HEADER Header;
    char Content[];

    PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Content));
} LX_GNS_JSON_MESSAGE, *PLX_GNS_JSON_MESSAGE;

using PCLX_INIT_NETWORK_INFORMATION = const LX_INIT_NETWORK_INFORMATION*;

typedef struct _LX_INIT_STOP_PLAN9_SERVER
{
    static inline auto Type = LxInitMessageStopPlan9Server;
    using TResponse = RESULT_MESSAGE<bool>;

    MESSAGE_HEADER Header;
    bool Force;

    PRETTY_PRINT(FIELD(Header), FIELD(Force));
} LX_INIT_STOP_PLAN9_SERVER, *PLX_INIT_STOP_PLAN9_SERVER;

//
// Feature flags to provide runtime velocity support for Linux code.
//
// To use this, define a new flag, and set it as part of the initial
// configuration message in WslService if the relevant feature is enabled.
// Call UtilGetFeatureFlags to determine which flags are enabled from the
// Linux code.
//

typedef enum _LX_INIT_FEATURE_FLAGS
{
    LxInitFeatureNone = 0,
    LxInitFeatureVirtIo9p = 0x1,
    LxInitFeatureVirtIoFs = 0x2,
    LxInitFeatureDisable9pServer = 0x4,
    LxInitFeatureRootfsCompressed = 0x8,
    LxInitFeatureSystemDistro = 0x10,
    LxInitFeatureDnsTunneling = 0x20,
} LX_INIT_FEATURE_FLAGS,
    *PLX_INIT_FEATURE_FLAGS;

typedef struct _LX_INIT_CONFIGURATION_INFORMATION_RESPONSE
{
    static inline auto Type = LxInitMessageInitializeResponse;

    MESSAGE_HEADER Header;
    unsigned int Plan9Port;
    unsigned int DefaultUid;
    unsigned int InteropPort;
    bool SystemdEnabled;
    std::uint64_t PidNamespace;
    unsigned int FlavorIndex;
    unsigned int VersionIndex;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Plan9Port), FIELD(DefaultUid), FIELD(InteropPort), FIELD(SystemdEnabled), FIELD(PidNamespace), STRING_FIELD(FlavorIndex), STRING_FIELD(VersionIndex));
} LX_INIT_CONFIGURATION_INFORMATION_RESPONSE, *PLX_INIT_CONFIGURATION_INFORMATION_RESPONSE;

using PCLX_INIT_CONFIGURATION_INFORMATION_RESPONSE = const LX_INIT_CONFIGURATION_INFORMATION_RESPONSE*;

//
// The data communicating initial configuration information for the instance.
// This contains the hostname, domainname, entries from the Windows hosts file,
// and the DrvFs volumes to mount.
//

typedef struct _LX_INIT_CONFIGURATION_INFORMATION
{
    static inline auto Type = LxInitMessageInitialize;
    using TResponse = LX_INIT_CONFIGURATION_INFORMATION_RESPONSE;

    MESSAGE_HEADER Header;
    unsigned int HostnameOffset;
    unsigned int DomainnameOffset;
    unsigned int WindowsHostsOffset;
    unsigned int DistributionNameOffset;
    unsigned int Plan9SocketOffset;
    unsigned int TimezoneOffset;
    unsigned int DrvFsVolumesBitmap;
    unsigned int DrvFsDefaultOwner;
    unsigned int FeatureFlags;
    LX_INIT_DRVFS_MOUNT DrvfsMount;
    char Buffer[];

    PRETTY_PRINT(
        FIELD(Header),
        STRING_FIELD(HostnameOffset),
        STRING_FIELD(DomainnameOffset),
        STRING_FIELD(WindowsHostsOffset),
        STRING_FIELD(Plan9SocketOffset),
        STRING_FIELD(TimezoneOffset),
        FIELD(DrvFsVolumesBitmap),
        FIELD(DrvFsDefaultOwner),
        FIELD(FeatureFlags),
        FIELD(DrvfsMount));

} LX_INIT_CONFIGURATION_INFORMATION, *PLX_INIT_CONFIGURATION_INFORMATION;

using PCLX_INIT_CONFIGURATION_INFORMATION = const LX_INIT_CONFIGURATION_INFORMATION*;

//
// The data communicating timezone information. The structure contains the IANA
// timezone identifier.
//

typedef struct _LX_INIT_TIMEZONE_INFORMATION
{
    static inline auto Type = LxInitMessageTimezoneInformation;

    MESSAGE_HEADER Header;
    unsigned int TimezoneOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), STRING_FIELD(TimezoneOffset));
} LX_INIT_TIMEZONE_INFORMATION, *PLX_INIT_TIMEZONE_INFORMATION;

using PCLX_INIT_TIMEZONE_INFORMATION = const LX_INIT_TIMEZONE_INFORMATION*;

//
// Flags to provide runtime behavior for create process.
//

typedef enum _LX_INIT_CREATE_PROCESS_FLAGS
{
    LxInitCreateProcessFlagsNone = 0,
    LxInitCreateProcessFlagsStdInConsole = 0x1,
    LxInitCreateProcessFlagsStdOutConsole = 0x2,
    LxInitCreateProcessFlagsStdErrConsole = 0x4,
    LxInitCreateProcessFlagsElevated = 0x8,
    LxInitCreateProcessFlagsInteropEnabled = 0x10,
    LxInitCreateProcessFlagAllowOOBE = 0x20,
} LX_INIT_CREATE_PROCESS_FLAGS,
    *PLX_INIT_CREATE_PROCESS_FLAGS;

typedef struct _LX_INIT_CREATE_PROCESS_UTILITY_VM
{
    static inline auto Type = LxInitMessageCreateProcessUtilityVm;
    using TResponse = RESULT_MESSAGE<uint32_t>;

    MESSAGE_HEADER Header;
    unsigned short Rows;
    unsigned short Columns;
    LX_INIT_CREATE_PROCESS_COMMON Common;

    PRETTY_PRINT(FIELD(Header), FIELD(Rows), FIELD(Columns));
} LX_INIT_CREATE_PROCESS_UTILITY_VM, *PLX_INIT_CREATE_PROCESS_UTILITY_VM;

using PCLX_INIT_CREATE_PROCESS_UTILITY_VM = const LX_INIT_CREATE_PROCESS_UTILITY_VM*;

//
// The data for communicating process exit status.
//

typedef struct _LX_INIT_PROCESS_EXIT_STATUS
{
    static inline auto Type = LxInitMessageExitStatus;

    MESSAGE_HEADER Header;
    int ExitCode;

    PRETTY_PRINT(FIELD(Header), FIELD(ExitCode));
} LX_INIT_PROCESS_EXIT_STATUS, *PLX_INIT_PROCESS_EXIT_STATUS;

using PCLX_INIT_PROCESS_EXIT_STATUS = const LX_INIT_PROCESS_EXIT_STATUS*;

//
// The data for communicating window size changes.
//

typedef struct _LX_INIT_WINDOW_SIZE_CHANGED
{
    static inline auto Type = LxInitMessageWindowSizeChanged;

    MESSAGE_HEADER Header;
    unsigned short Rows;
    unsigned short Columns;

    PRETTY_PRINT(FIELD(Header), FIELD(Rows), FIELD(Columns));
} LX_INIT_WINDOW_SIZE_CHANGED, *PLX_INIT_WINDOW_SIZE_CHANGED;

using PCLX_INIT_WINDOW_SIZE_CHANGED = const LX_INIT_WINDOW_SIZE_CHANGED*;

//
// The data for terminating an instance.
//

typedef struct _LX_INIT_TERMINATE_INSTANCE
{
    static inline auto Type = LxInitMessageTerminateInstance;
    using TResponse = RESULT_MESSAGE<bool>;

    MESSAGE_HEADER Header;
    bool Force;

    PRETTY_PRINT(FIELD(Header), FIELD(Force));
} LX_INIT_TERMINATE_INSTANCE, *PLX_INIT_TERMINATE_INSTANCE;

using PCLX_INIT_TERMINATE_INSTANCE = const LX_INIT_TERMINATE_INSTANCE*;

//
// The data for beginning a socket relay.
//

typedef struct _LX_INIT_START_SOCKET_RELAY
{
    static inline auto Type = LxInitMessageStartSocketRelay;

    MESSAGE_HEADER Header;
    unsigned short Family;
    unsigned short Port;
    int HvSocketPort;
    size_t BufferSize;

    PRETTY_PRINT(FIELD(Header), FIELD(Family), FIELD(Port), FIELD(HvSocketPort), FIELD(BufferSize));
} LX_INIT_START_SOCKET_RELAY, *PLX_INIT_START_SOCKET_RELAY;

using PCLX_INIT_START_SOCKET_RELAY = const LX_INIT_START_SOCKET_RELAY*;

typedef struct _LX_INIT_MOUNT_DRVFS
{
    static inline auto Type = LxInitMessageRemountDrvfs;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    bool Admin;
    unsigned int VolumesToMount;
    unsigned int UnreadableVolumes;
    int DefaultOwnerUid;

    PRETTY_PRINT(FIELD(Header), FIELD(Admin), FIELD(VolumesToMount), FIELD(UnreadableVolumes), FIELD(DefaultOwnerUid));
} LX_INIT_MOUNT_DRVFS, PLX_INIT_MOUNT_DRVFS;

typedef struct _LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE
{
    static inline auto Type = LxInitMessageAddVirtioFsDeviceResponse;

    MESSAGE_HEADER Header;
    int Result;
    unsigned int TagOffset;
    unsigned int SourceOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Result), STRING_FIELD(TagOffset), STRING_FIELD(SourceOffset));
} LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE, *PLX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE;

typedef struct _LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE
{
    static inline auto Type = LxInitMessageAddVirtioFsDevice;
    using TResponse = LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE;

    MESSAGE_HEADER Header;
    bool Admin;
    unsigned int PathOffset;
    unsigned int OptionsOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Admin), STRING_FIELD(PathOffset), STRING_FIELD(OptionsOffset));
} LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE, *PLX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE;

typedef struct _LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE
{
    static inline auto Type = LxInitMessageRemountVirtioFsDevice;
    using TResponse = LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE;

    MESSAGE_HEADER Header;
    bool Admin;
    unsigned int TagOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Admin), STRING_FIELD(TagOffset));
} LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE, *PLX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE;

//
// The messages that can be sent to mini_init.
//

typedef enum _LX_MINI_INIT_MESSAGE_FLAGS
{
    LxMiniInitMessageFlagNone = 0,
    LxMiniInitMessageFlagMountReadOnly = 0x1,
    LxMiniInitMessageFlagCreateOverlayFs = 0x2,
    LxMiniInitMessageFlagLaunchSystemDistro = 0x4,
    LxMiniInitMessageFlagExportCompressGzip = 0x8,
    LxMiniInitMessageFlagExportCompressXzip = 0x10,
    LxMiniInitMessageFlagVerbose = 0x20,
} LX_MINI_INIT_MESSAGE_FLAGS,
    *PLX_MINI_INIT_MESSAGE_FLAGS;

typedef enum _LX_MINI_INIT_MOUNT_DEVICE_TYPE
{
    LxMiniInitMountDeviceTypeInvalid = 0,
    LxMiniInitMountDeviceTypeLun = 0x1,
    LxMiniInitMountDeviceTypePmem = 0x2,
} LX_MINI_INIT_MOUNT_DEVICE_TYPE,
    *PLX_MINI_INIT_MOUNT_DEVICE_TYPE;

typedef struct _LX_MINI_INIT_MESSAGE
{
    static inline auto Type = LxMiniInitMessageLaunchInit;

    MESSAGE_HEADER Header;
    LX_MINI_INIT_MOUNT_DEVICE_TYPE MountDeviceType;
    unsigned int DeviceId;
    unsigned int FsTypeOffset;
    unsigned int MountOptionsOffset;
    unsigned int VmIdOffset;
    unsigned int DistributionNameOffset;
    unsigned int SharedMemoryRootOffset;
    unsigned int InstallPathOffset;
    unsigned int UserProfileOffset;
    unsigned int Flags;
    unsigned int ConnectPort;
    char Buffer[];

    PRETTY_PRINT(
        FIELD(Header),
        FIELD(MountDeviceType),
        FIELD(DeviceId),
        STRING_FIELD(FsTypeOffset),
        STRING_FIELD(MountOptionsOffset),
        STRING_FIELD(DistributionNameOffset),
        STRING_FIELD(SharedMemoryRootOffset),
        STRING_FIELD(InstallPathOffset),
        STRING_FIELD(UserProfileOffset),
        FIELD(Flags),
        FIELD(ConnectPort));

} LX_MINI_INIT_MESSAGE, *PLX_MINI_INIT_MESSAGE;

using PCLX_MINI_INIT_MESSAGE = const LX_MINI_INIT_MESSAGE*;

typedef enum _LX_MINI_INIT_MEMORY_RECLAIM_MODE
{
    LxMiniInitMemoryReclaimModeDisabled,
    LxMiniInitMemoryReclaimModeGradual,
    LxMiniInitMemoryReclaimModeDropCache
} LX_MINI_INIT_MEMORY_RECLAIM_MODE,
    *PLX_MINI_INIT_MEMORY_RECLAIM_MODE;

typedef struct _LX_MINI_INIT_EARLY_CONFIG_MESSAGE
{
    static inline auto Type = LxMiniInitMessageEarlyConfig;

    MESSAGE_HEADER Header;
    unsigned int SwapLun;
    LX_MINI_INIT_MOUNT_DEVICE_TYPE SystemDistroDeviceType;
    unsigned int SystemDistroDeviceId;
    int PageReportingOrder;
    LX_MINI_INIT_MEMORY_RECLAIM_MODE MemoryReclaimMode;
    // IPv4 address stored in network byte order
    uint32_t DnsTunnelingIpAddress = 0;
    bool EnableDebugShell;
    bool EnableDnsTunneling;
    bool EnableSafeMode;
    bool DefaultKernel;
    unsigned int KernelModulesDeviceId;
    unsigned int HostnameOffset;
    unsigned int KernelModulesListOffset;
    char Buffer[];

    PRETTY_PRINT(
        FIELD(Header),
        FIELD(SwapLun),
        FIELD(SystemDistroDeviceType),
        FIELD(SystemDistroDeviceId),
        FIELD(PageReportingOrder),
        FIELD(MemoryReclaimMode),
        FIELD(DnsTunnelingIpAddress),
        FIELD(EnableDebugShell),
        FIELD(EnableDnsTunneling),
        FIELD(EnableSafeMode),
        FIELD(DefaultKernel),
        FIELD(KernelModulesDeviceId),
        STRING_FIELD(HostnameOffset),
        STRING_FIELD(KernelModulesListOffset));
} LX_MINI_INIT_EARLY_CONFIG_MESSAGE, *PLX_MINI_INIT_EARLY_CONFIG_MESSAGE;

using PCLX_MINI_INIT_EARLY_CONFIG_MESSAGE = const LX_MINI_INIT_EARLY_CONFIG_MESSAGE*;

typedef enum _LX_MINI_INIT_PORT_TRACKER_TYPE
{
    LxMiniInitPortTrackerTypeNone,
    LxMiniInitPortTrackerTypeMirrored,
    LxMiniInitPortTrackerTypeRelay,
} LX_MINI_INIT_PORT_TRACKER_TYPE,
    *PLX_MINI_INIT_PORT_TRACKER_TYPE;

typedef enum _LX_MINI_INIT_NETWORKING_MODE
{
    LxMiniInitNetworkingModeNone = 0,
    LxMiniInitNetworkingModeNat = 1,
    LxMiniInitNetworkingModeBridged = 2,
    LxMiniInitNetworkingModeMirrored = 3,
    LxMiniInitNetworkingModeVirtioProxy = 4
} LX_MINI_INIT_NETWORKING_MODE,
    *PLX_MINI_INIT_NETWORKING_MODE;

typedef struct _LX_MINI_INIT_NETWORKING_CONFIGURATION
{
    LX_MINI_INIT_NETWORKING_MODE NetworkingMode;
    LX_MINI_INIT_PORT_TRACKER_TYPE PortTrackerType;
    uint16_t EphemeralPortRangeStart; // Both Start and End are inclusive
    uint16_t EphemeralPortRangeEnd;
    bool EnableDhcpClient;
    bool DisableIpv6;
    int DhcpTimeout;
} LX_MINI_INIT_NETWORKING_CONFIGURATION, *PLX_MINI_INIT_NETWORKING_CONFIGURATION;

typedef struct _LX_MINI_INIT_CONFIG_MESSAGE
{
    static inline auto Type = LxMiniInitMessageInitialConfig;

    MESSAGE_HEADER Header;
    int EntropySize;
    unsigned int EntropyOffset;
    bool EnableGuiApps;
    bool MountGpuShares;
    bool EnableInboxGpuLibs;
    LX_MINI_INIT_NETWORKING_CONFIGURATION NetworkingConfiguration;
    char Buffer[];

    PRETTY_PRINT(
        FIELD(Header),
        FIELD(EntropySize),
        FIELD(MountGpuShares),
        FIELD(EntropyOffset),
        FIELD(EnableInboxGpuLibs),
        FIELD(NetworkingConfiguration.NetworkingMode),
        FIELD(NetworkingConfiguration.PortTrackerType),
        FIELD(NetworkingConfiguration.EphemeralPortRangeStart),
        FIELD(NetworkingConfiguration.EphemeralPortRangeEnd),
        FIELD(NetworkingConfiguration.EnableDhcpClient),
        FIELD(NetworkingConfiguration.DisableIpv6),
        FIELD(NetworkingConfiguration.DhcpTimeout));

} LX_MINI_INIT_CONFIG_MESSAGE, *PLX_MINI_INIT_CONFIG_MESSAGE;

using PCLX_MINI_INIT_CONFIG_MESSAGE = const LX_MINI_INIT_CONFIG_MESSAGE*;

typedef struct _LX_MINI_INIT_TELEMETRY_MESSAGE
{
    static inline auto Type = LxMiniInitTelemetryMessage;

    MESSAGE_HEADER Header;
    bool ShowDrvFsNotification;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(ShowDrvFsNotification), BUFFER_FIELD(Buffer));

} LX_MINI_INIT_TELEMETRY_MESSAGE, *PLX_MINI_INIT_TELEMETRY_MESSAGE;

using PCLX_MINI_INIT_TELEMETRY_MESSAGE = const LX_MINI_INIT_TELEMETRY_MESSAGE*;

typedef struct _LX_MINI_INIT_MOUNT_MESSAGE
{
    static inline auto Type = LxMiniInitMessageMount;

    MESSAGE_HEADER Header;
    unsigned int PartitionIndex; // 0 means the disk directly
    unsigned int ScsiLun;
    unsigned int TypeOffset;
    unsigned int TargetNameOffset;
    unsigned int OptionsOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(PartitionIndex), FIELD(ScsiLun), STRING_FIELD(TypeOffset), STRING_FIELD(TargetNameOffset), STRING_FIELD(OptionsOffset));

} LX_MINI_INIT_MOUNT_MESSAGE, *PLX_MINI_INIT_MOUNT_MESSAGE;

using PCLX_MINI_INIT_MOUNT_MESSAGE = const LX_MINI_INIT_MOUNT_MESSAGE*;

typedef struct _LX_MINI_INIT_UNMOUNT_MESSAGE
{
    static inline auto Type = LxMiniInitMessageUnmount;

    MESSAGE_HEADER Header;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
} LX_MINI_INIT_UNMOUNT_MESSAGE, *PLX_MINI_INIT_UNMOUNT_MESSAGE;

typedef struct _LX_MINI_INIT_DETACH_MESSAGE
{
    static inline auto Type = LxMiniInitMessageDetach;

    MESSAGE_HEADER Header;
    unsigned int ScsiLun;

    PRETTY_PRINT(FIELD(Header), FIELD(ScsiLun));
} LX_MINI_INIT_DETACH_MESSAGE, *PLX_MINI_INIT_DETACH_MESSAGE;

using PCLX_MINI_INIT_UNMOUNT_MESSAGE = const LX_MINI_INIT_UNMOUNT_MESSAGE*;

typedef enum _LX_MINI_MOUNT_STEP
{
    LxMiniInitMountStepNone = 0,
    LxMiniInitMountStepFindDevice = 0x1,
    LxMiniInitMountStepFindPartition = 0x2,
    LxMiniInitMountStepMount = 0x3,
    LxMiniInitMountStepUnmount = 0x4,
    LxMiniInitMountStepRmDir = 0x5,
    LxMiniInitMountStepDetectFilesystem = 0x6,
} LX_MINI_MOUNT_STEP,
    *PLX_MINI_MOUNT_STEP;

typedef struct _LX_MINI_INIT_MOUNT_RESULT_MESSAGE
{
    static inline auto Type = LxMiniInitMessageMountStatus;

    MESSAGE_HEADER Header;
    int Result;
    LX_MINI_MOUNT_STEP FailureStep;

    PRETTY_PRINT(FIELD(Header), FIELD(Result), FIELD(FailureStep));

} LX_MINI_INIT_MOUNT_RESULT_MESSAGE, *PLX_MINI_INIT_MOUNT_RESULT_MESSAGE;

using PCLX_MINI_INIT_MOUNT_RESULT_MESSAGE = const LX_MINI_INIT_MOUNT_RESULT_MESSAGE*;

typedef struct _LX_INIT_GUEST_CAPABILITIES
{
    static inline auto Type = LxMiniInitMessageGuestCapabilities;

    MESSAGE_HEADER Header;
    bool SeccompAvailable;
    char Buffer[]; // Contains the kernel version string

    PRETTY_PRINT(FIELD(Header), FIELD(SeccompAvailable), BUFFER_FIELD(Buffer));
} LX_INIT_GUEST_CAPABILITIES, *PLX_INIT_GUEST_CAPABILITIES;

typedef struct _LX_MINI_INIT_WAIT_FOR_PMEM_DEVICE_MESSAGE
{
    static inline auto Type = LxMiniInitMessageWaitForPmemDevice;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    unsigned int PmemId;

    PRETTY_PRINT(FIELD(Header), FIELD(PmemId));
} LX_MINI_INIT_WAIT_FOR_PMEM_DEVICE_MESSAGE, *PLX_MINI_INIT_WAIT_FOR_PMEM_DEVICE_MESSAGE;

typedef struct _LX_MINI_INIT_CHILD_EXIT_MESSAGE
{
    static inline auto Type = LxMiniInitMessageChildExit;

    MESSAGE_HEADER Header;
    unsigned int ChildPid;

    PRETTY_PRINT(FIELD(Header), FIELD(ChildPid));
} LX_MINI_INIT_CHILD_EXIT_MESSAGE, *PLX_MINI_INIT_CHILD_EXIT_MESSAGE;

typedef struct _LX_MINI_INIT_MOUNT_FOLDER_MESSAGE
{
    static inline auto Type = LxMiniInitMountFolder;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    bool ReadOnly;
    unsigned int PathIndex;
    unsigned int NameIndex;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(ReadOnly), STRING_FIELD(PathIndex), STRING_FIELD(NameIndex));
} LX_MINI_INIT_MOUNT_FOLDER_MESSAGE, *PLX_MINI_INIT_MOUNT_FOLDER_MESSAGE;

typedef struct _LX_MINI_INIT_RESIZE_DISTRIBUTION_RESPONSE
{
    static inline auto Type = LxMiniInitMessageResizeDistributionResponse;

    MESSAGE_HEADER Header;
    uint32_t ResponseCode;

    PRETTY_PRINT(FIELD(Header), FIELD(ResponseCode));
} LX_MINI_INIT_RESIZE_DISTRIBUTION_RESPONSE, *PLX_MINI_INIT_RESIZE_DISTRIBUTION_RESPONSE;

typedef struct _LX_MINI_INIT_RESIZE_DISTRIBUTION_MESSAGE
{
    static inline auto Type = LxMiniInitMessageResizeDistribution;

    MESSAGE_HEADER Header;
    unsigned int ScsiLun;
    uint64_t NewSize;

    PRETTY_PRINT(FIELD(Header), FIELD(ScsiLun), FIELD(NewSize));
} LX_MINI_INIT_RESIZE_DISTRIBUTION_MESSAGE, *PLX_MINI_INIT_RESIZE_DISTRIBUTION_MESSAGE;

struct CREATE_PROCESS_MESSAGE
{
    static inline auto Type = LxInitCreateProcess;

    MESSAGE_HEADER Header;
    unsigned int PathIndex;
    unsigned int CommandLineIndex;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), STRING_FIELD(PathIndex), STRING_FIELD(CommandLineIndex));
};

struct EJECT_VHD_MESSAGE
{
    static inline auto Type = LxMiniInitMessageEjectVhd;
    using TResponse = RESULT_MESSAGE<int32_t>;

    MESSAGE_HEADER Header;
    uint32_t Lun;

    PRETTY_PRINT(FIELD(Header), FIELD(Lun));
};

typedef enum _LX_MINI_CREATE_INSTANCE_STEP
{
    LxInitCreateInstanceStepNone = 0,
    LxInitCreateInstanceStepFormatDisk = 0x1,
    LxInitCreateInstanceStepMountDisk = 0x2,
    LxInitCreateInstanceStepLaunchSystemDistro = 0x3,
    LxInitCreateInstanceStepLaunchInit = 0x3,
    LxInitCreateInstanceStepRunTar = 0x4
} LX_MINI_CREATE_INSTANCE_STEP,
    *PLX_MINI_CREATE_INSTANCE_STEP;

typedef struct _LX_MINI_INIT_CREATE_INSTANCE_RESULT
{
    static inline auto Type = LxMiniInitMessageCreateInstanceResult;

    MESSAGE_HEADER Header;
    int Result;
    _LX_MINI_CREATE_INSTANCE_STEP FailureStep;
    uint64_t Pid;
    uint32_t ConnectPort;
    unsigned int WarningsOffset;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Result), FIELD(FailureStep), FIELD(Pid), FIELD(ConnectPort), STRING_FIELD(WarningsOffset));
} LX_MINI_INIT_CREATE_INSTANCE_RESULT, *P_LX_MINI_INIT_CREATE_INSTANCE_RESULT;

typedef struct _LX_MINI_INIT_IMPORT_RESULT
{
    static inline auto Type = LxMiniInitMessageImportResult;

    MESSAGE_HEADER Header;
    int Result;
    bool ValidDistribution;
    unsigned int FlavorIndex;
    unsigned int VersionIndex;
    unsigned int ShortcutIconIndex;
    unsigned int ShortcutIconSize;
    unsigned int DefaultNameIndex;
    unsigned int TerminalProfileIndex;
    unsigned int TerminalProfileSize;
    bool GenerateTerminalProfile;
    bool GenerateShortcut;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), FIELD(Result), STRING_FIELD(FlavorIndex), STRING_FIELD(VersionIndex), STRING_FIELD(DefaultNameIndex), FIELD(ShortcutIconIndex), FIELD(TerminalProfileIndex));
} LX_MINI_INIT_IMPORT_RESULT, *PLX_MINI_INIT_IMPORT_RESULT;

typedef struct _LX_INIT_OOBE_RESULT
{
    static inline auto Type = LxInitOobeResult;

    MESSAGE_HEADER Header;
    uint32_t Result;
    int64_t DefaultUid;

    PRETTY_PRINT(FIELD(Header), FIELD(Result), FIELD(DefaultUid));
} LX_INIT_OOBE_RESULT, *PLX_INIT_OOBE_RESULT;

typedef struct _LX_INIT_QUERY_VM_ID
{
    static inline auto Type = LxInitMessageQueryVmId;

    MESSAGE_HEADER Header;
    char Buffer[];

    PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
} LX_INIT_QUERY_VM_ID, *PLX_INIT_QUERY_VM_ID;

template <>
struct std::formatter<LX_MESSAGE_TYPE, char>
{
    template <typename TCtx>
    static constexpr auto parse(TCtx& ctx)
    {
        return ctx.begin();
    }

    template <typename TCtx>
    auto format(LX_MESSAGE_TYPE str, TCtx& ctx) const
    {
        return std::format_to(ctx.out(), "{}", ToString(str));
    }
};

template <>
struct std::formatter<LX_MINI_INIT_MOUNT_DEVICE_TYPE, char>
{
    template <typename TCtx>
    static constexpr auto parse(TCtx& ctx)
    {
        return ctx.begin();
    }

    template <typename TCtx>
    auto format(LX_MINI_INIT_MOUNT_DEVICE_TYPE str, TCtx& ctx) const
    {
        return std::format_to(ctx.out(), "{}", static_cast<int>(str));
    }
};
