/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/*                                                                        */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* OBJECT CODE ONLY SOURCE MATERIALS                                      */
/*                                                                        */
/* (C) COPYRIGHT International Business Machines Corp. 2000,2019          */
/* All Rights Reserved                                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/*****************************************************************************/
/*                                                                           */
/*         Topology Services Network Interface Module (NIM)                  */
/*                                                                           */
/*         nim_interface.h: this file contains the definitions and data      */
/*         structures that are used in the communication between the         */
/*         Topology Services daemon and the NIM processes.                   */
/*                                                                           */
/*         Communication between the daemon and the NIMs occurs through      */
/*         a Unix-Domain socket. A number of command, responses, and         */
/*         notifications is defined in this file.                            */
/*                                                                           */
/*****************************************************************************/
/* sccsid = "@(#)24   1.21   src/rsct/pts/pam/nim/nim_interface.h, topology.services, rsct_rady, rady2035a 1/18/18 07:18:26" */

#ifndef _NIM_INTERFACE_h
#define _NIM_INTERFACE_h


#ifdef __cplusplus
extern "C" {
#endif

/*
 * Includes
 */

#include <inttypes.h>    /* 64-bit types (in AIX inttypes.h warns against
                            including this file directly, but this file
                            seems to be the only one that is common in AIX
                            and Linux and has 64-bit data type definitions) */
#include <sys/types.h>   /* for ushort */
#include <sys/socket.h>  /* needed by if.h */
#include <net/if.h>      /* for IFNAMSIZ */
#include <netinet/in.h>  /* sockaddr_in */
#include <rsct/ct.h>



#if defined(_AIX) || defined(__sun)
   /*  AIX or SUN */
   #pragma pack(4)           /* produce 4-byte aligned data structure */
#elif defined(__linux__) || defined(__INTERIX)
   /* Linux or Interix */
   #pragma pack(push)        /* to save the previous pack configuration */
   #pragma pack(4)           /* produce 4-byte aligned data structure */
#endif


/*
 * Return codes of the NIM process
 *
 * Values 1--100 are reserved for errno in the exec() call
 */

#define HA_NIM_EXIT_OK          0 /* OK (NIM was told to exit) */
#define HA_NIM_EXIT_UDS_CONN  101 /* cannot connect to Unix-domain socket */
#define HA_NIM_EXIT_INT_ERR   102 /* NIM internal error */
#define HA_NIM_EXIT_INV_PAR   103 /* invalid parameter to NIM */

/*
 * Types of messages exchanged between the HATS daemon and the NIM
 */

typedef enum {
    /* HATS daemon -> NIM */
    HA_NIM_OPEN = 1,              /* open connection to local adapter */
    HA_NIM_CLOSE,                 /* close connection with local adapter */
    HA_NIM_START_HB,              /* start sending heartbeats */
    HA_NIM_MONITOR_HB,            /* start monitoring heartbeats */
    HA_NIM_SEND_MSG,              /* send a message to a peer daemon */
    HA_NIM_STOP_HB,               /* stop sending heartbeats */
    HA_NIM_STOP_MONITOR,          /* stop monitoring heartbeats */
    HA_NIM_ARE_YOU_ALIVE,         /* requests response from NIM */
    HA_NIM_EXIT,                  /* exit */
    HA_NIM_DMS_START,             /* start updating DMS timer */
    HA_NIM_DMS_STOP,              /* stop updating DMS timer */
    HA_NIM_START_THREAD_REPORTS,  /* begin reporting thread blockage */
    HA_NIM_STOP_THREAD_REPORTS,   /* quit reporting thread blockage */

    /* NIM -> HATS daemon */
    HA_NIM_OPEN_RESPONSE  = 30,   /* response to open --
                                     need room for expansion */
    HA_NIM_ADAPTER_STATUS,        /* adapter status */
    HA_NIM_INCOMING_MSG,          /* a message arrived from peer daemon */
    HA_NIM_REMOTE_ADAPTER_STAT,   /* information about remote adapter */
    HA_NIM_ERROR,                 /* error in NIM */
    HA_NIM_I_AM_ALIVE,            /* response to HA_NIM_ARE_YOU_ALIVE */
    HA_NIM_INFO,                  /* NIM returns information */
    HA_NIM_REMOTE_NODE_HALT,      /* message when NIM sees remote halt */
    HA_NIM_THREADS_BLOCKED        /* Reports statistics of blocked threads */
} nim_msg_type_t;


/*
 * Size of the interface name used on some platforms for IPv6 socket binding
 */
#define NIM_IF_LEN 32


/*
 * Interface version number
 */


#define NIM_MSG_VERSION_MAJOR   (1)
#define NIM_MSG_VERSION_MINOR   (1)

typedef struct { ushort major, minor;} nim_msg_version_t;

#define set_nim_msg_version(__major, __minor, ver)  ver.major = __major; \
                                                    ver.minor = __minor;

#define nim_msg_version_is_equal(ver1, ver2) ((ver1.major == ver2.major) && \
                                              (ver1.minor == ver2.minor))

#define nim_msg_version_is_greater_equal(ver1, ver2) ((ver1.major >   \
                                                       ver2.major) || \
                                        ((ver1.major == ver2.major) &&\
                                         (ver1.minor >= ver2.minor)))

#define nim_msg_version_as_int(v) (int)(v.major * 1000 + v.minor)

#define NIM_MSG_MAX_SIZE  40000         /* maximum message size for this
                                           version */

/*
 * Message header format
 */

typedef struct {
    ct_uint32_t   size;            /* size of the rest of the message */
    nim_msg_type_t     type;            /* type of the message */
    nim_msg_version_t  version;         /* interface version number */
    ct_uint32_t padding[3];      /* room for expansion */
} nim_msg_header_t;


/*
 * Format of an adapter address
 */

/* Address types */
#define NIM_ADDR_TYPE_IPv4          (ushort) 1     /* IPv4 address 
                                                      (struct sockaddr_in)*/
#define NIM_ADDR_TYPE_IPv6          (ushort) 2     /* IPv6 address
                                                      (struct sockaddr_in6) */
#define NIM_ADDR_TYPE_DEVNAME       (ushort) 3     /* null terminated device
                                                      name */
#define NIM_ADDR_TYPE_MNDHB         (ushort) 4     /* Fake IPv4 address
                                                      (struct sockaddr_in) */

/* IPv6 */
/* Boosted the following from 100 to 130 as INET6_ADDRSTRLEN is 30 bytes 
 * more than INET_ADDRSTRLEN. */
#define NIM_MAX_ADDR_SIZE           130            /* max size of header +
                                                      actual address */

typedef struct {
    ct_uint16_t addrtype;         /* type of address */
    ct_uint16_t	addrlen;          /* length of address */
    char             addr[2];          /* the address: variable size */
} nim_adap_addr_t;

#define sizeof_adap_addr_hdr(x)  (sizeof(x->addrtype) + sizeof(x->addrlen))

#define sizeof_adap_addr(x)      (sizeof(x->addrtype) + sizeof(x->addrlen) + \
                                  (size_t)x->addrlen)

#define nim_addr_copy(dest, src) \
                     memcpy((void *)dest, \
                            (void *)src,  \
                            sizeof_adap_addr(src))

/* IPv6 */
/* The following expect nim_adap_addr_union_t for the addresses */

/* Compare to adddresses. Returns false if they are not same or not
   same type. */
#define COMP_ADDR(a,b) (((a).addrtype == NIM_ADDR_TYPE_IPv4) ? \
                         ((a).addrtype == (b).addrtype) && \
                        ((a).u.ipv4addr.sin_addr.s_addr == \
                         (b).u.ipv4addr.sin_addr.s_addr) : \
                        ((a).addrtype == NIM_ADDR_TYPE_IPv6) ? \
                         ((a).addrtype == (b).addrtype) && \
                         IN6_ARE_ADDR_EQUAL(&(a).u.ipv6addr.sin6_addr, \
                                            &(b).u.ipv6addr.sin6_addr) : \
                         0)

/* Return the Address family for a given type */
#define IP_FAM(a) (((a).addrtype == NIM_ADDR_TYPE_IPv4) ? \
                    AF_INET : \
                   ((a).addrtype == NIM_ADDR_TYPE_IPv6) ? \
                    AF_INET6 : \
                    0)

/* Return a pointer cast as struck sockaddr* to the address */
#define SOCK_PTR(a) (((a).addrtype == NIM_ADDR_TYPE_IPv4) ? \
                     (struct sockaddr *)&(a).u.ipv4addr : \
                    ((a).addrtype == NIM_ADDR_TYPE_IPv6) ? \
                     (struct sockaddr *)&(a).u.ipv6addr : \
                     (struct sockaddr *)NULL)

/* Return size of socket address for the given type */
#define SOCK_LEN(a) (((a).addrtype == NIM_ADDR_TYPE_IPv4) ? \
                     sizeof(struct sockaddr_in) : \
                    ((a).addrtype == NIM_ADDR_TYPE_IPv6) ? \
                     sizeof(struct sockaddr_in6) : \
                     0)

#define NIM_MAX_DEVNAME_LEN         (NIM_MAX_ADDR_SIZE - 2 * sizeof(ushort))
                                                   /* max size of a device
                                                      name */

/*
 * Format of a daemon-daemon packet. The NIM needs to have some
 * minimum information about how a daemon-daemon packet looks like
 * to be able to do some level of validation and to distinguish
 * between a heartbeat packet and a non-heartbeat packet.
 *
 * The declaration of the "real" packet is in lib/comm_lib.h.
 */

typedef ct_uint32_t nim_GSgid_t[2];

/* The heartbeat packet is the only one that the NIM needs to worry about */
typedef enum {
    HA_NIM_HEART_BEAT = 0xA,
    HA_NIM_PING       = 0x15
} nim_daemon_packet_kind_t;

typedef struct {
    int32_t                   Treceive[2];
    nim_daemon_packet_kind_t  kind;
    ct_int32_t		      len;
    ct_int32_t                fill1[3];
    nim_GSgid_t               from_group;  /* source group of the packet */
    ct_int32_t                fill2[2];
    nim_GSgid_t               to_group;    /* destination group of the packet */
    ct_int32_t                fill3[5];
    /* Defect 111477 - making fill3[] one smaller so machinesInst can be
       explicit, since it is now used to determine if heartbeats are valid */
    ct_int32_t                  machinesInst;
} nim_daemon_packet_t;


/*
 * Data structures used for the HA_NIM_OPEN command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - local address (nim_adap_addr_t - variable size)
 *               - number of other local adapters
 *               - array of other local addresses (nim_adap_addr_t)
 *               - number of remote adapters
 *               - array of remote addresses (nim_adap_addr_t)
 *               - open data (nim_open_data_t)
 */

#define NIM_OPEN_SPECIAL_DATA      8  /* number of ints passed to NIM */

typedef struct {
    ct_uint32_t     min_packet_size;  /* minimum packet size */
    ct_uint32_t     max_packet_size;  /* maximum packet size */
    ct_uint32_t     num_send_retries; /* number of retries when sending msg */
    ct_uint32_t     bcast_enabled;    /* bcast enabled for this adapter */
    ct_uint32_t     no_ping;          /* do not ping to determine status */
    char            interface_name[NIM_IF_LEN]; /* Interface name */
    ct_int32_t      special_data[NIM_OPEN_SPECIAL_DATA];
                                      /* special data passed to NIM */
} nim_open_data_t;


/*
 * Data structures used for the HA_NIM_OPEN_RESPONSE response
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - status data (nim_open_response_data_t)
 *               - bcast/multicast address (nim_adap_addr_t - variable size)
 */

/* status of HA_NIM_OPEN request */
typedef enum {
     HA_NIM_OPEN_OK,                  /* open request successful */
     HA_NIM_ADDRESS_MISSING,          /* address not configured in
                                         any adapter */
     HA_NIM_CANNOT_BIND_UDS,          /* cannot bind to UNIX-domain socket */
     /* XXX if cannot bind then will not be able to respond via the UDS
        interface either!!! */
     HA_NIM_CANNOT_BIND_SOC,          /* cannot bind to IP socket */
     HA_NIM_CANNOT_OPEN_DEV,          /* cannot open the device (non-IP) */
     HA_NIM_SYSCALL_ERROR,            /* error in system call */
     HA_NIM_NETMON_ERROR,             /* error in netmon library */
     HA_NIM_BCAST_ADDR_ERROR          /* inconsistent broadcast address */
} nim_open_response_status_t;

#define HA_NIM_MAX_FCT_NAME   64      /* max function name */

typedef struct {
    nim_open_response_status_t status;/* status of open request */
    ct_int32_t errno_val;                    /* errno value */
    ct_int32_t error_code;                   /* error given by netmon library */
    char fct_name[HA_NIM_MAX_FCT_NAME];
                                      /* function that returned error */
    ct_int32_t bcast_flag;                   /* does adapter support broadcast? */
    char ifname[IFNAMSIZ];            /* interface name */
    /* XXX missing: MTU, subnet mask, ?? */
} nim_open_response_data_t;


/* get open response as a string */
#define get_open_response_status_string(st)  \
    ((st == HA_NIM_OPEN_OK) ? "HA_NIM_OPEN_OK" :                      \
     (st == HA_NIM_ADDRESS_MISSING) ? "HA_NIM_ADDRESS_MISSING" :      \
     (st == HA_NIM_CANNOT_BIND_UDS) ? "HA_NIM_CANNOT_BIND_UDS" :      \
     (st == HA_NIM_CANNOT_BIND_SOC) ? "HA_NIM_CANNOT_BIND_SOC" :      \
     (st == HA_NIM_CANNOT_OPEN_DEV) ? "HA_NIM_CANNOT_OPEN_DEV" :      \
     (st == HA_NIM_SYSCALL_ERROR) ? "HA_NIM_SYSCALL_ERROR" :          \
     (st == HA_NIM_NETMON_ERROR) ? "HA_NIM_NETMON_ERROR" :            \
     (st == HA_NIM_BCAST_ADDR_ERROR) ? "HA_NIM_BCAST_ADDR_ERROR" :    \
      "<Unknown response>")


/*
 * Data structures used for the HA_NIM_ADAPTER_STATUS status report
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - adapter status (nim_adapter_status_t)
 */

typedef enum {
    HA_NIM_ADAPTER_IS_UP = 1,         /* adapter is up */
    HA_NIM_ADAPTER_IF_FLAG_DOWN,      /* adapter's interface flag is down */
    HA_NIM_ADAPTER_IS_DOWN,           /* adapter is down (no incoming packets)*/
    HA_NIM_ADAPTER_IS_MISCONFIGURED,  /* adapter is misconfigured */
    HA_NIM_ADAPTER_NETMON_ERROR       /* error in netmon library */
} nim_adapter_state_t;


typedef struct {
    nim_adapter_state_t state;        /* up/down state of adapter */
    ct_int32_t errno_val;                    /* errno value */
    char fct_name[HA_NIM_MAX_FCT_NAME];
                                      /* function that returned error */
    ct_int32_t error_code;                   /* error given by netmon library */
} nim_adapter_status_t;

/* get adapter status as a string */
#define get_open_adapter_status_string(st)                                 \
    ((st == HA_NIM_ADAPTER_IS_UP) ? "HA_NIM_ADAPTER_IS_UP" :               \
     (st == HA_NIM_ADAPTER_IF_FLAG_DOWN) ? "HA_NIM_ADAPTER_IF_FLAG_DOWN" : \
     (st == HA_NIM_ADAPTER_IS_DOWN) ? "HA_NIM_ADAPTER_IS_DOWN" :           \
     (st == HA_NIM_ADAPTER_IS_MISCONFIGURED) ?                             \
            "HA_NIM_ADAPTER_IS_MISCONFIGURED" :                            \
     (st == HA_NIM_ADAPTER_NETMON_ERROR) ? "HA_NIM_ADAPTER_NETMON_ERROR" : \
      "UNKNOWN_STATUS")


/*
 * Data structures used for the HA_NIM_REMOTE_ADAPTER_STAT status report
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - address (nim_adap_addr_t - variable size)
 *               - adapter status (nim_adapter_status_t)
 */




/*
 * Format of "daemon messages" (for example, heartbeat packet passed in
 * HA_NIM_START_HB, or the message sent with HA_NIM_SEND_MSG or
 * received in HA_NIM_INCOMING_MSG)
 *
 *    - Destination/source address (nim_adap_addr_t)
 *    - message length (int -- 32bits)
 *    - the message itself
 */


/*
 * Data structures used for the HA_NIM_START_HB command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - daemon message (including destination address)
 *               - heartbeat information (nim_hb_send_info_t)
 */

typedef struct {
    ct_uint32_t how_often_msec;            /* how often to send the heartbeats
                                          (in msec) */
} nim_hb_send_info_t;

/*
 * Data structures used for the HA_NIM_STOP_HB command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - neighbor address (nim_adap_addr_t -- variable size)
 */


/*
 * Data structures used for the HA_NIM_SEND_MSG command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - daemon message (including destination address)
 */



/*
 * Data structures used for the HA_NIM_MONITOR_HB command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - neighbor address (nim_adap_addr_t)
 *               - heartbeat monitoring info (nim_hb_monitor_info_t)
 */

/*
 * Data type to represent a "ping grace period" value that is specified
 * by the user is passed from the daemon to the NIM
 */
typedef ct_int32_t nim_ping_grace_period_t;

typedef struct {
    nim_GSgid_t group;                /* group id of expected message */
    ct_uint32_t how_often_msec;            /* how often to expect the heartbeats
                                          (in msec) */
    ct_uint32_t sensitivity;               /* how many heartbeats to miss before
                                         telling daemon about it */
    /* Defect 111477 - Need the instance number in the NIM so we can handle
       heartbeats with the wrong instance number correctly */
    uint32_t machinesInst;            /* Current instance number */
    nim_ping_grace_period_t hb_monitor_ping_grace_period_msec;
                                      /* grace period value in millisecs */
} nim_hb_monitor_info_t;

/*
 * Default value for the grace period, meaning "NIM will choose grace
 * period value"
 */
#define NIM_PING_GRACE_PERIOD_DEFAULT_VALUE  ((nim_ping_grace_period_t)-1)


/*
 * Data structures used for the HA_NIM_STOP_MONITOR command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - neighbor address (nim_adap_addr_t -- variable size)
 */


/*
 * Data structures used for the HA_NIM_DMS_START command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 */

/*
 * Data structures used for the HA_NIM_DMS_STOP command
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 */


/*
 * Data structures used for the HA_NIM_I_AM_ALIVE response
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - NIM statistics (nim_statistics_t)
 *               - vendor info (nim_vendor_info_t)
 */

/*
 * Format of the statistics block passed back from NIM to daemon
 */

#define NIM_NUM_GEN_STATS  8

typedef struct {
    uint64_t        packets_sent;         /* number of packets sent */
    uint64_t        icmp_packets_sent;    /* number of ICMP packets sent */
    uint64_t        packets_rcvd;         /* number of packets received */
    uint64_t        icmp_packets_rcvd;    /* number of ICMP packets received */
    uint64_t        send_errors;          /* number of errors when sending */
    uint64_t        no_mbuf_send_errors;  /* number of ENOBUFS when sending */
    uint64_t        dropped;              /* number of packets dropped by
                                             NIM filters */
    uint64_t        missed_hbs_current;   /* number of missed heartbeats for
                                             current group */
    uint64_t        missed_hbs_total;     /* total number of missed heartbeats
                                             since device was opened */
    uint64_t        data[NIM_NUM_GEN_STATS];
                                          /* NIM-specific statistics */
} nim_statistics_t;

/*
 * Format of the vendor information passed from NIM back to daemon
 */

#define NIM_VENDOR_STRING_SIZE    64

typedef struct {
    char   vendor[NIM_VENDOR_STRING_SIZE];   /* vendor name */
    char   version[NIM_VENDOR_STRING_SIZE];  /* version string */
    char   date[NIM_VENDOR_STRING_SIZE];     /* date string */
} nim_vendor_info_t;


/*
 * Data structures used for the HA_NIM_ERROR response
 *
 * Format of packet is:
 *               - header (nim_msg_header_t)
 *               - severity level (nim_error_level_t)
 *               - error code (nim_error_code_t)
 *               - generic error values
 *               - error string
 */

/* error levels */
typedef enum {
    HA_NIM_ERROR_LEVEL_FATAL = 1,         /* fatal error; NIM will exit */
    HA_NIM_ERROR_LEVEL_ERROR,             /* (possibly) recoverable error */
    HA_NIM_ERROR_LEVEL_INFO               /* information or non-fatal error */
} nim_error_level_t;


/* error codes */
typedef enum {
    HA_NIM_ERROR_CODE_INTERNAL,           /* internal error */
    HA_NIM_ERROR_CODE_STUCK,              /* a thread was stuck for too long */
    HA_NIM_ERROR_CODE_READ,               /* read error */
    HA_NIM_ERROR_CODE_WRITE,              /* write error */
    HA_NIM_ERROR_CODE_INVAL_REQ,          /* invalid request from daemon */
    HA_NIM_ERROR_CODE_VERSION,            /* protocol version not supported */
    HA_NIM_ERROR_CODE_INPUT_TRAFFIC,      /* excessive input msg traffic */
    HA_NIM_ERROR_CODE_OUTPUT_TRAFFIC,     /* excessive outgoing msg traffic */
    HA_NIM_ERROR_CODE_OTHER = 50          /* other error. Must be last */
} nim_error_code_t;


#define HA_NIM_MAX_ERROR_STRING    256    /* length of error string */

typedef struct {
    nim_error_level_t error_level;        /* error level */
    nim_error_code_t  error_code;         /* error code */
    ct_int32_t value1;             /* value 1 */
    ct_int32_t value2;             /* value 2 */
    char              error_string[HA_NIM_MAX_ERROR_STRING];
                                          /* NULL-terminated error string */
} nim_error_data_t;


// Similar to nim_msg_header_t, but it actually reserves the memory space
// for the address.  Moved from nim_data.h so this type would be available
// to nim_driver
typedef struct {
    ct_uint16_t addrtype;              // type of address
    ct_uint16_t addrlen;               // length of address
    union {
        struct sockaddr_in  ipv4addr;       // an IPv4 address
        struct sockaddr_in6 ipv6addr;       // an IPv6 address
        char dev_name[NIM_MAX_DEVNAME_LEN]; // a device name
    } u;
} nim_adap_addr_union_t;


// Details section of HA_NIM_THREADS_BLOCKED message
#define NIM_BLOCKED_THREAD_NAME_SZ  16
typedef struct {
    char thread_name[NIM_BLOCKED_THREAD_NAME_SZ];
    ct_int32_t msecs_blocked;  // time blocked in milliseconds
} nim_blocked_thread_details_t;


#if defined(_AIX) || defined(__sun)
   /* AIX or SUN */
   #pragma pack()                  /* turn off forcing of 4-byte alignment.*/
#elif defined(__linux__) || defined(__INTERIX)
   /* Linux or Interix */
   #pragma pack(pop)                  /* turn off forcing of 4-byte alignment.*/
#endif


#ifdef __cplusplus
}                                       /* end extern "C" */
#endif



#endif   /* _NIM_INTERFACE_h */
