/*++

Copyright (C) Microsoft Corporation, 1991 - 1999

Module Name:

    osfpcket.hxx

Abstract:

    This file contains the packet formats for the OSF Connection Oriented
    RPC protocol.

Author:

    Michael Montague (mikemon) 23-Jul-1990

Revision History:

    07-Mar-1992    mikemon

        Added comments and cleaned it up.

--*/

#ifndef __OSFPCKET_HXX__
#define __OSFPCKET_HXX__

#define OSF_RPC_V20_VERS 5
#define OSF_RPC_V20_VERS_MINOR 0

typedef enum
{
    rpc_request = 0,
    rpc_response = 2,
    rpc_fault = 3,
    rpc_bind = 11,
    rpc_bind_ack = 12,
    rpc_bind_nak = 13,
    rpc_alter_context = 14,
    rpc_alter_context_resp = 15,
    rpc_auth_3 = 16,
    rpc_shutdown = 17,
    rpc_cancel = 18,
    rpc_orphaned = 19,
    rpc_rts = 20
} rpc_ptype_t;

#define PFC_FIRST_FRAG           0x01
#define PFC_LAST_FRAG            0x02
#define PFC_PENDING_CANCEL        0x04
                              // 0x08 reserved
#define PFC_CONC_MPX             0x10
#define PFC_DID_NOT_EXECUTE      0x20
#define PFC_MAYBE                0x40
#define PFC_OBJECT_UUID          0x80

typedef struct
{
    unsigned short length;
    unsigned char port_spec[1];
} port_any_t;

typedef unsigned short p_context_id_t;

typedef struct
{
    GUID if_uuid;
    unsigned long if_version;
} p_syntax_id_t;

typedef struct
{
    p_context_id_t p_cont_id;
    unsigned char n_transfer_syn;
    unsigned char reserved;
    p_syntax_id_t abstract_syntax;
    p_syntax_id_t transfer_syntaxes[1];
} p_cont_elem_t;

typedef struct
{
    unsigned char n_context_elem;
    unsigned char reserved;
    unsigned short reserved2;
    p_cont_elem_t p_cont_elem[1];
} p_cont_list_t;

typedef unsigned short p_cont_def_result_t;

#define acceptance 0
#define user_rejection 1
#define provider_rejection 2

typedef unsigned short p_provider_reason_t;

#define reason_not_specified 0
#define abstract_syntax_not_supported 1
#define proposed_transfer_syntaxes_not_supported 2
#define local_limit_exceeded 3

typedef unsigned short p_reject_reason_t;

#define reason_not_specified_reject 0
#define temporary_congestion 1
#define local_limit_exceeded_reject 2
#define protocol_version_not_supported 4
#define authentication_type_not_recognized 8
#define invalid_checksum 9

typedef struct
{
    p_cont_def_result_t result;
    p_provider_reason_t reason;
    p_syntax_id_t transfer_syntax;
} p_result_t;

typedef struct
{
    unsigned char n_results;
    unsigned char reserved;
    unsigned short reserved2;
    p_result_t p_results[1];
} p_result_list_t;

typedef struct
{
    unsigned char major;
    unsigned char minor;
} version_t;

typedef version_t p_rt_version_t;

typedef struct
{
    // currently, the runtime uses only one version.
    // if we change that, we have to change the alignment
    // of the members after that so that they are still
    // naturally aligned
    unsigned char n_protocols;
    p_rt_version_t p_protocols[1];
} p_rt_versions_supported_t;

typedef struct
{
    unsigned char rpc_vers;
    unsigned char rpc_vers_minor;
    unsigned char PTYPE;
    unsigned char pfc_flags;
    unsigned char drep[4];
    unsigned short frag_length;
    unsigned short auth_length;
    unsigned long call_id;
} rpcconn_common;

typedef struct
{
    rpcconn_common common;
    unsigned short max_xmit_frag;
    unsigned short max_recv_frag;
    unsigned long assoc_group_id;
} rpcconn_bind;

#if defined(WIN32RPC) || defined(MAC)
#pragma pack(2)
#endif // WIN32RPC
typedef struct
{
    rpcconn_common common;
    unsigned short max_xmit_frag;
    unsigned short max_recv_frag;
    unsigned long assoc_group_id;
    unsigned short sec_addr_length;
} rpcconn_bind_ack;
#if defined(WIN32RPC) || defined(MAC)
#pragma pack()
#endif // WIN32RPC

typedef struct
{
    rpcconn_common common;
    p_reject_reason_t provider_reject_reason;
    p_rt_versions_supported_t versions;
    UUID Signature;
#if defined (_WIN64)
    // on Win64, we need to align the buffer after
    // this to 16 byte boundary. That's why the padding
    ULONG Padding[2];
#endif
    char buffer[1];
} rpcconn_bind_nak;

const size_t BindNakSizeWithoutEEInfoAndSignature = FIELD_OFFSET(rpcconn_bind_nak, Signature);
const size_t BindNakSizeWithoutEEInfo = FIELD_OFFSET(rpcconn_bind_nak, buffer);

extern const UUID *BindNakEEInfoSignature;

inline size_t GetEEInfoSizeFromBindNakPacket (rpcconn_bind_nak *BindNak)
{
    ASSERT (BindNak->common.frag_length > BindNakSizeWithoutEEInfo);
    ASSERT (RpcpMemoryCompare(&BindNak->Signature, BindNakEEInfoSignature, sizeof(UUID)) == 0);
    return (BindNak->common.frag_length - BindNakSizeWithoutEEInfo);
}

const int MinimumBindNakLength = 21;

typedef struct
{
    rpcconn_common common;
    unsigned char auth_type;
    unsigned char auth_level;

#ifndef WIN32RPC

    unsigned short pad;

#endif // WIN32RPC
} rpcconn_auth3;

typedef rpcconn_bind rpcconn_alter_context;

typedef struct
{
    rpcconn_common common;
    unsigned short max_xmit_frag;
    unsigned short max_recv_frag;
    unsigned long assoc_group_id;
    unsigned short sec_addr_length;
    unsigned short pad;
} rpcconn_alter_context_resp;

typedef struct
{
    rpcconn_common common;
    unsigned long alloc_hint;
    p_context_id_t p_cont_id;
    unsigned short opnum;
} rpcconn_request;

typedef struct
{
    rpcconn_common common;
    unsigned long alloc_hint;
    p_context_id_t p_cont_id;
    unsigned char alert_count;
    unsigned char reserved;
} rpcconn_response;

const unsigned char FaultEEInfoPresent = 1;

typedef struct
{
    rpcconn_common common;
    unsigned long alloc_hint;
    p_context_id_t p_cont_id;
    unsigned char alert_count;
    unsigned char reserved;
    unsigned long status;
    unsigned long reserved2;
    // present only if reserved & FaultEEInfoPresent
    // the actual length is alloc_hint - FIELD_OFFSET(rpcconn_fault, buffer)
    unsigned char buffer[1];
} rpcconn_fault;

const size_t FaultSizeWithoutEEInfo = FIELD_OFFSET(rpcconn_fault, buffer);

inline size_t GetEEInfoSizeFromFaultPacket (rpcconn_fault *Fault)
{
    ASSERT (Fault->reserved & FaultEEInfoPresent);
    ASSERT (Fault->alloc_hint > 0);
    return (Fault->alloc_hint - FaultSizeWithoutEEInfo);
}

typedef struct
{
    unsigned char auth_type;
    unsigned char auth_level;
    unsigned char auth_pad_length;
    unsigned char auth_reserved;
    unsigned long auth_context_id;
} sec_trailer;

typedef struct tagChannelSettingCookie
{
    char Cookie[16];
} ChannelSettingCookie;

#define COOKIE_SIZE_IN_BYTES    16
#define MAX_IPv4_ADDRESS_SIZE   4
#define MAX_IPv6_ADDRESS_SIZE   (16 + 4)        // address + scope_id
#define MAX_ADDRESS_SIZE        max(MAX_IPv4_ADDRESS_SIZE, MAX_IPv6_ADDRESS_SIZE)

#define RTS_FLAG_PING               0x1
#define RTS_FLAG_OTHER_CMD          0x2
#define RTS_FLAG_RECYCLE_CHANNEL    0x4
#define RTS_FLAG_IN_CHANNEL         0x8
#define RTS_FLAG_OUT_CHANNEL        0x10
#define RTS_FLAG_EOF                0x20
#define RTS_FLAG_ECHO               0x40

typedef enum tagClientAddressType
{
    catIPv4 = 0,
    catIPv6
} ClientAddressType;

typedef struct tagChannelSettingClientAddress
{
    // provide enough storage for IPv6 address. Declared in this
    // form to avoid general runtime dependency on transport headers
    // In reality this is SOCKADDR_IN for IPv4 and SOCKADDR_IN6 for
    // IPv6
    ClientAddressType AddressType;
    union
        {
        /*[case(catIPv4)]*/ char IPv4Address[MAX_IPv4_ADDRESS_SIZE];
        /*[case(catIPv6)]*/ char IPv6Address[MAX_IPv6_ADDRESS_SIZE];
        } u;
} ChannelSettingClientAddress;

typedef enum tagForwardDestinations
{
    fdClient = 0,
    fdInProxy,
    fdServer,
    fdOutProxy
} ForwardDestinations;

typedef struct tagFlowControlAck
{
    ULONG BytesReceived;
    ULONG AvailableWindow;
    ChannelSettingCookie ChannelCookie;
} FlowControlAck;

typedef enum tagTunnelSettingsCommandTypes
{
    tsctReceiveWindowSize = 0,      // 0
    tsctFlowControlAck,             // 1
    tsctConnectionTimeout,          // 2
    tsctCookie,                     // 3
    tsctChannelLifetime,            // 4
    tsctClientKeepalive,            // 5
    tsctVersion,                    // 6
    tsctEmpty,                      // 7
    tsctPadding,                    // 8
    tsctNANCE,                      // 9
    tsctANCE,                       // 10
    tsctClientAddress,              // 11
    tsctAssociationGroupId,         // 12
    tsctDestination,                // 13
    tsctPingTrafficSentNotify       // 14
} TunnelSettingsCommandTypes;

#define LAST_RTS_COMMAND    (tsctPingTrafficSentNotify)

extern const int TunnelSettingsCommandTypeSizes[];

typedef struct tagTunnelSettingsCommand
{
    unsigned long CommandType;
    union 
        {
        /*[case(tsctReceiveWindowSize)]*/   ULONG ReceiveWindowSize;
        /*[case(tsctFlowControlAck)]*/      FlowControlAck Ack;
        /*[case(tsctConnectionTimeout)]*/   ULONG ConnectionTimeout; // in milliseconds
        /*[case(tsctCookie)]*/              ChannelSettingCookie Cookie;
        /*[case(tsctChannelLifetime)]*/     ULONG ChannelLifetime;
        /*[case(tsctClientKeepalive)]*/     ULONG ClientKeepalive;  // in milliseconds
        /*[case(tsctVersion)]*/             ULONG Version;
        /*[case(tsctEmpty)] ; */            // empty - no operands
        /*[case(tsctPadding)] ; */          ULONG ConformanceCount;  // in bytes
        /*[case(tsctNANCE)] ; */            // NANCE - negative acknowledgement for new channel
                                            // establishment - no operands
        /*[case(tsctANCE)] ; */             // ANCE - acknowledge new channel establishment
        /*[case(tsctClientAddress)]*/       ChannelSettingClientAddress ClientAddress;
        /*[case(tsctAssociationGroupId)]*/  ChannelSettingCookie AssociationGroupId;
        /*[case(tsctDestination)]*/         ULONG Destination;   // actually one of ForwardDestinations
        /*[case(tsctPingTrafficSentNotify)]*/ ULONG PingTrafficSent;    // in bytes
        } u;
} TunnelSettingsCommand;

typedef struct {
    rpcconn_common common;
    unsigned short Flags;
    unsigned short NumberOfSettingCommands;
    TunnelSettingsCommand Cmd[1];   // the actual size depends on NumberOfSettings
} rpcconn_tunnel_settings;

#define SIZE_OF_RTS_CMD_AND_PADDING(Command) \
    (TunnelSettingsCommandTypeSizes[Command] \
    + ConstPadN(TunnelSettingsCommandTypeSizes[Command], 4))

#define MUST_RECV_FRAG_SIZE 2048

#define NDR_DREP_ASCII 0x00
#define NDR_DREP_EBCDIC 0x01
#define NDR_DREP_CHARACTER_MASK 0x0F
#define NDR_DREP_BIG_ENDIAN 0x00
#define NDR_DREP_LITTLE_ENDIAN 0x10
#define NDR_DREP_ENDIAN_MASK 0xF0
#define NDR_DREP_IEEE 0x00
#define NDR_DREP_VAX 0x01
#define NDR_DREP_CRAY 0x02
#define NDR_DREP_IBM 0x03

#ifdef MAC
#define NDR_LOCAL_CHAR_DREP  NDR_DREP_ASCII
#define NDR_LOCAL_INT_DREP   NDR_DREP_BIG_ENDIAN
#define NDR_LOCAL_FP_DREP    NDR_DREP_IEEE
#else
#define NDR_LOCAL_CHAR_DREP  NDR_DREP_ASCII
#define NDR_LOCAL_INT_DREP   NDR_DREP_LITTLE_ENDIAN
#define NDR_LOCAL_FP_DREP    NDR_DREP_IEEE
#endif

/*++

Routine Description:

    This macro determines whether or not we need to do endian data
    conversion.

Argument:

    drep - Supplies the four byte data representation.

Return Value:

    A value of non-zero indicates that endian data conversion needs to
    be performed.

--*/
#define DataConvertEndian(drep) \
    ( (drep[0] & NDR_DREP_ENDIAN_MASK) != NDR_LOCAL_INT_DREP )

/*++

Routine Description:

    This macro determines whether or not we need to do character data
    conversion.

Argument:

    drep - Supplies the four byte data representation.

Return Value:

    A value of non-zero indicates that character data conversion needs to
    be performed.

--*/
#define DataConvertCharacter(drep) \
    ( (drep[0] & NDR_DREP_CHARACTER_MASK) != NDR_LOCAL_CHAR_DREP)

void
ConstructPacket (
    IN OUT rpcconn_common PAPI * Packet,
    IN unsigned char PacketType,
    IN unsigned int PacketLength
    );

RPC_STATUS
ValidatePacket (
    IN rpcconn_common PAPI * Packet,
    IN unsigned int PacketLength
    );

void
ByteSwapSyntaxId (
    IN p_syntax_id_t PAPI * SyntaxId
    );

#if 0
void
ConvertStringEbcdicToAscii (
    IN unsigned char * String
    );
#endif

extern unsigned long __RPC_FAR
MapToNcaStatusCode (
    IN RPC_STATUS RpcStatus
    );

extern RPC_STATUS __RPC_FAR
MapFromNcaStatusCode (
    IN unsigned long NcaStatus
    );

#if 1
#define CoAllocateBuffer(_x_) RpcAllocateBuffer((_x_))
#define CoFreeBuffer(_x_) RpcFreeBuffer((_x_))
#else
#define CoAllocateBuffer(_x_) RpcpFarAllocate((_x_))
#define CoFreeBuffer(_x_) RpcpFarFree((_x_))
#endif

#endif // __OSFPCKET_HXX__