/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72X src/bos/kernel/sys/ethchan.h 1.48.9.2                           */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1999,2022              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/* @(#)82   1.48.9.2  src/bos/kernel/sys/ethchan.h, sysxentchan, bos72X, x2022_09A0 2/23/22 17:43:42 */

/*
 *      COMPONENT_NAME: sysxentchan
 *
 *      ORIGINS: 27
 *
 *      NOTES:
 *              Header file containing structures and #defines for the
 *              EtherChannel kernel extension.
 */

#ifndef _H_ETHCHAN
#define _H_ETHCHAN

#include <sys/types.h>
#include <sys/err_rec.h>
#include <sys/cdli_entuser.h>
#include <sys/cdli_entuser.ethchan.h>
#include <sys/ethernet_mibs.h>
#include <sys/watchdog.h>
#include <net/net_globals.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip6_icmp.h>
#include <netinet/if_ether.h>

/* jumbo packet max data size */
#define JUMBO_MAX_MTU 9014

/* The biggest size a link-layer header could possibly have */
#define MAX_LINKHDR             24

/* Used for converting numbers represented as strings to numbers */
#define islower(c)              ((c>='a') && (c<='z'))
#define isdigit(c)              ((c>='0') && (c<='9'))

#define DIGIT(x)                (isdigit(x) ? (x) - '0' : \
                                islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')

#define ETHCHAN_TRACE_SIZE      (1000 * 8) /* Maximum number of trace */
#define ETHCHAN_OPLEVEL         (PL_IMP)

/* This macro decides whether the provided device is a virtual device
 * (i.e. not really a physical device) or not: this is used to know whether
 * the idle channel should have a different MAC address than the active
 * channel (which is the case with virtual devices)
 * List of virtual devices: Host Ethernet Adapter (HEA)
 */
#define IS_HEA_DEVICE(nddp) \
        (((nddp->ndd_2_flags & NDD_2_HEA))? TRUE: FALSE)

/* These constants are used in the statistics to signal which channel
 * is active, or if a backup has not even been defined
 */
#define BACKUP_NOT_DEFINED      0
#define PRIMARY_CHANNEL_ACTIVE  1
#define BACKUP_ADAPTER_ACTIVE   2

/* This constant defines how many gratuitous ARP packets are sent
 * after a failover. Since now a recovery will only take place when we
 * are sure that the primary channel's port has been initialized by the
 * switch, we are pretty sure that the first ARP packets will be sent
 * out correctly. However, to avoid regressions, we will leave this value
 * pretty high and avoid potential problems.
 */
#define ARP_SEND_MAX            30

/* This constant is used when probing gratuitous ARP packets are to be set
 * continuously; after a failover, when the primary channel recovers we
 * will send out probing ARP packets, and when any of these packets
 * or actually, any other packet, is received by the primary channel, we
 * know for sure that its port has been initialized and we can proceed
 * to recover the EtherChannel to the primary channel.
 * Since we do not know how many seconds it will take for the primary
 * channel's port to be initialized, we will keep sending ARPs forever
 * (or until the primary channel fails again or the EtherChannel is closed).
 * We must do this to make sure that there is broadcast traffic on the
 * network for the primary channel to "listen to."
 */
#define ARP_SEND_INFINITY       23456

/* These constants are used to identify the reason why a failover occurred:
 * it may have been due to all the adapters in the channel having failed,
 * or if the ping feature in netif_backup is enabled, it may also be due to
 * the failure of the ping attempts
 */
#define ECH_CHANNEL_FAILURE     0
#define ECH_PING_FAILURE        1

/* These constants identify the current state of the EtherChannel */
#define ECH_DOWN                (0x00000000)
#define ECH_UP                  (0x11111111)
#define ECH_SWITCHING           (0x22222222)

/* Specifies the maximum length of an adapter's name */
#ifndef ECH_ADAPNAME_SIZE
#define ECH_ADAPNAME_SIZE       ERR_NAMESIZE
#endif

/* -------------------------------------------------------------------- */
/* Error Log Structures                                                 */
/* -------------------------------------------------------------------- */

/* Defines for error logger */

/* This failure code value indicates an adapter has gone down */
#define ECH_FC_LINK_FAIL        0

/* This failure code value indicates the remote host could not be pinged */
#define ECH_FC_NET_FAIL         1

typedef struct error_log_no_adapters
{
    struct  err_rec0 errhead;
} error_log_no_adapters_t;

typedef struct error_log_one_adapter
{
    struct  err_rec0 errhead;
    uchar_t adapter1[ECH_ADAPNAME_SIZE];
} error_log_one_adapter_t;

typedef struct error_log_two_adapters
{
    struct  err_rec0 errhead;
    uchar_t adapter1[ECH_ADAPNAME_SIZE];
    uchar_t adapter2[ECH_ADAPNAME_SIZE];
} error_log_two_adapters_t;

/* -------------------------------------------------------------------- */
/* Define Device Structure                                              */
/* -------------------------------------------------------------------- */
/* These flags are used to specify the operating mode of the EtherChannel */
#define ECH_STANDARD_MODE               0x01    /* Sets the channel to select the
                                                 * adapter using an algorithm
                                                 */
#define ECH_ROUND_ROBIN_MODE            0x02    /* Sets the channel to send over
                                                 * the adapters in round robin fashion
                                                 */
#define ECH_8023AD_MODE                 0x04    /* Sets the channel to use the IEEE
                                                 * 802.3ad protocol 
                                                 */
#define ECH_NETIF_BACKUP_MODE           0x08    /* Only for internal use, since
                                                 * netif_backup is no longer an
                                                 * explicit mode
                                                 */
#define ECH_TEAMING_MODE                0x10    /* Sets the channel to teaming
                                                 * mode - only one (primary) 
                                                 * channel, determines receive
                                                 * adapter so switch configuration
                                                 * isn't needed
                                                 */ 

/* These flags are used to specify the hashing mode of the EtherChannel */
#define ECH_HASH_DST_IP                 0x01    /* Hashes on the last byte of the
                                                 * destination IP address
                                                 */
#define ECH_HASH_PORT_MODE              0x10    /* Signals that hashing is done on
                                                 * TCP/UDP port (used to group
                                                 * together the following modes)
                                                 */
#define ECH_HASH_SRC_PORT               0x11    /* Hashes on the TCP/UDP source 
                                                 * port only
                                                 */
#define ECH_HASH_DST_PORT               0x12    /* Hashes on the TCP/UDP destination
                                                 * port only
                                                 */
#define ECH_HASH_SRC_DST_PORT           0x14    /* Hashes on both the TCP/UDP
                                                 * destination and source ports
                                                 */

#define IP_OFFMASK                      0x1FFF  /* Used to get the fragment offset from
                                                 * the "ip_off" field from the "ip"
                                                 * structure
                                                 */

#define ECH_8023AD_LONG_INTERVAL        0x01    /* Signals that long interval
                                                 * is used for sending LACPDU
                                                 * in 802.3ad mode
                                                 */

#define ECH_8023AD_SHORT_INTERVAL       0x02    /* Signals that short interval
                                                 * is used for sending LACPDU
                                                 * in 802.3ad mode
                                                 */

typedef struct ethchan_dds
{
    uint32_t locator;                       /* "ECDD", for debugging */
    uchar_t lname[ECH_ADAPNAME_SIZE];       /* Device logical name (i.e. ent5) */
    uchar_t alias[ECH_ADAPNAME_SIZE];       /* Alias to the device (i.e. en5) */
    uint32_t no_of_adapters;                /* Number of adapters in the channel */
    uint32_t no_of_backup_adapters;         /* Number of backup adapters in the channel */
    uchar_t adapter_names[MAXIFPERCHAN][ECH_ADAPNAME_SIZE];
    /* Device logical names of the
     * adapters forming the channel
     */
    uchar_t jumbo_frames;           /* If non-zero, set the MTU to that
                                     * of jumbo frames
                                     */
    uchar_t mode;                   /* Sets the mode for accessing the
                                     * adapters
                                     */
    uchar_t use_alt_addr;           /* TRUE => use the following
                                     * alt_addr otherwise use the address
                                     * from the adapter
                                     */
    uchar_t alt_addr[ENT_NADR_LENGTH];

    uint32_t netaddr;               /* If in Network Interface Backup
                                     * mode, ping this address periodically
                                     * to detect network failures
                                     */
    uint32_t num_retries;           /* The number of pings that may go
                                     * unanswered before a failover is
                                     * triggered
                                     */
    uint32_t retry_to;              /* Time in seconds in between ping
                                     * attempts
                                     */
    uchar_t backup_adapter_names[MAXIFPERCHAN][ECH_ADAPNAME_SIZE];
                                    /* Name of the backup adapter */

    uchar_t hash_mode;              /* Hashing mode */

    boolean_t automatic_recovery;   /* True if automatic recovery should
                                     * be performed, false otherwise
                                     */

    boolean_t lossless_failover;    /* True if lossless failover should
                                     * be performed, false otherwise
                                     */

    boolean_t mac_swap;             /* True if backup adapter should retain
                                     * its MAC and primary and backup MACs
                                     * should be swapped on failover.
                                     */

    uchar_t interval;               /* LACPDU interval for 802.3ad mode */
} ethchan_dds_t;

/* -------------------------------------------------------------------- */
/*      CCS Device Driver Variables                                     */
/* -------------------------------------------------------------------- */
typedef struct ethchan_drw_lock
{
    DRW_lock rw_lock;               /* Disabled read/write lock.
                                     */
    int32_t  dr_refcnt;             /* reference count used for
                                     * dynamic reconfig operation.
                                     */
} ethchan_drw_lock_t;

typedef struct ethchan_dev
{
    uint32_t        locator;        /* "ECDV", for debugging */
    uint32_t        state;          /* This field holds the state of
                                     * the device driver
                                     */
    /* -------------------------------------------- */
    /* The counter section.  For the ctl options    */
    /* -------------------------------------------- */
    uint32_t        adap_switches;  /* Count of the number of times the
                                     * channel has failed over
                                     */
    uint32_t        multi_cnt;      /* Count of the number of times the
                                     * channel has had multicast enabled
                                     * (used to know when to reset the
                                     * NDD_MULTICAST flag)
                                     */
    uint32_t        prom_cnt;       /* Count of the number of times the
                                     * channel has been put in promiscuous
                                     * mode (used to know when to reset the
                                     * NDD_PROMISC flag)
                                     */
    struct watchdog wdt;            /* Timer used to send ping packets
                                     * periodically when said feature is
                                     * enabled
                                     */
    Simple_lock     lock;           /* Locks control functions for the
                                     * device
                                     */
    uint32_t        locked;         /* We need a lock that can be held
                                     * for code with no lock (we are
                                     * employing a flag that will be
                                     * checked when the lock is obtained
                                     * and if the flag is set, the lock
                                     * is released, until the flag is
                                     * cleared, and then the process is
                                     * repeated until the lock is
                                     * available).
                                     */
    struct sockaddr_in sa;          /* The IP address of the host we will
                                     * ping, if that feature is enabled
                                     */
    struct watchdog arp_timer;      /* Timer used to send several
                                     * gratuitous ARP packets after a
                                     * failover
                                     */
    struct watchdog team_info_timer;/* Timer used to clear team_info
                                     * linked lists for teaming mode
                                     */
    uint32_t        arp_cnt;        /* Count of how many ARP packets have
                                     * been sent after a failover
                                     */
    time_t          ndd_stime;      /* Time when the adapter is restarted
                                     */
    struct watchdog lacpdu_sender_timer;
                                    /* Timer that checks if a LACPDU must
                                     * be sent and sends one if necessary
                                     */
    struct watchdog lacpdu_periodic_timer;
                                    /* Timer that sends a LACPDU
                                     * periodically
                                     */
    ethchan_drw_lock_t ethchan_lock;/* EtherChannel disabled lock
                                     */
    int32_t         refcnt;         /* Number of functions that are
                                     * using data structures that should
                                     * not be changed, but are unable to
                                     * do so while holding the lock
                                     */
    void (*ls_func)();              /* Pointer to link status callback
                                     * function registered by container
                                     * device
                                     */
    void            *ls_param;      /* Parameter to the link status
                                     * callback function
                                     */
    struct watchdog lacpdu_timeout_timer;
                                    /* Timer that determines if any
                                     * LACPDU is missed.
                                     */
    Simple_lock     filter_lock;    /* Locking syncronization between
                                     * adding and deleting of filters
                                     */
    boolean_t       lacp_channel_init_done;
                                    /* This flag will force wait failover to
                                     * allow primary channel to negotiate LACP
                                     */
    Simple_lock     link_lock;      /* Lock syncronization between
                                     * link state change
                                     */
} ethchan_dev_t;

typedef char ethchan_addr_t[ENT_NADR_LENGTH];

/* The "lacpdu_t" structure describes a LACPDU, the type of packet
 * exchanged by the protocol used by IEEE 802.3ad Link Aggregation mode
 */
typedef struct lacpdu
{
    uchar_t         subtype;
    uchar_t         version;
    uchar_t         actor_tlv_type;
    uchar_t         actor_information_length;
    ushort_t        actor_system_priority;
    uchar_t         actor_system [6];
    ushort_t        actor_key;
    ushort_t        actor_port_priority;
    ushort_t        actor_port;
    uchar_t         actor_state;
    uchar_t         actor_reserved [3];
    uchar_t         partner_tlv_type;
    uchar_t         partner_information_length;
    ushort_t        partner_system_priority;
    uchar_t         partner_system [6];
    ushort_t        partner_key;
    ushort_t        partner_port_priority;
    ushort_t        partner_port;
    uchar_t         partner_state;
    uchar_t         partner_reserved [3];
    uchar_t         collector_tlv_type;
    uchar_t         collector_information_length;
    ushort_t        collector_max_delay;
    uchar_t         collector_reserved [12];
    uchar_t         terminator_tlv_type;
    uchar_t         terminator_length;
    uchar_t         terminator_reserved [50];
} lacpdu_t;

/* The "marker_pdu_t" structure describes a marker PDU, the type of packet
 * exchanged to mark when a port should stop being used for transmission
 * in case of dynamic port reallocation
 */
typedef struct marker_pdu
{
    uchar_t         subtype;
    uchar_t         version;
    uchar_t         requester_tlv_type;
    uchar_t         requester_information_length;
    ushort_t        requester_port;
    uchar_t         requester_system [6];
    uint32_t        requester_transaction_id;
    ushort_t        pad;
    uchar_t         terminator_tlv_type;
    uchar_t         terminator_length;
    uchar_t         terminator_reserved [90];
} marker_pdu_t;

/* Each port (adapter) in an IEEE 802.3ad aggregation will have one of
 * these structures to keep track of each port's run-time values
 * and the values of the port's partner; it also holds the port's
 * statistics
 */
typedef struct ieee8023ad_port_info
{
    ndd_t                           *nddp;
    boolean_t                       ntt;

    struct pkt
    {
        struct ether_header     header;
        lacpdu_t                lacpdu;
    } pkt;

    ieee_8023ad_stats_t             stats;
    boolean_t                       lacp_ready;
    /* Flag indicates whether
     * the port is lacp_ready
     * or not.
     */
    time_t                          receive_time;
    /* time at which LACPDU
     * is received on this port
     */
    boolean_t                       port_lacp_down_logged; /* Flag to indicate whether port lacp down
                                                            * error is logged or not
                                                            */
} ieee8023ad_port_info_t;

/* Contains information regarding the aggregator pertaining to an
 * EtherChannel; it contains structures for all the ports in an IEEE
 * 802.3ad aggregation (even the backup, if one is defined)
 */
typedef struct ieee8023ad_aggregator
{
    uint32_t                locator;        /* "ECAG", for debugging */
    ieee8023ad_port_info_t  port_info[MAXIFPERCHAN];
    /* Static array
     * of port_info structures;
     * there will be one port_info
     * structure for each adapter
     * in the main channel
     */
    ieee8023ad_port_info_t  backup_port_info[MAXIFPERCHAN];
    /* Static array
     * of port_info structures;
     * there will be one port_info
     * structure for each backup adapter
     * in the main channel
     */
    uchar_t                 aggregation_status;
    uchar_t                 backup_aggregation_status;
    /* Status of the link
     * aggregation: before the
     * protocol is initiated, it
     * is set to "Inactive"; then
     * it is set to "Negotiating".
     * When convergence has
     * been achieved, it is set
     * to "Aggregated", and if it
     * fails, to "Failed"
     */
    ns_user_t               ns_user;        /* The user for the filters
                                             * used to receive LACPDUs;
                                             * it is contained here
                                             * because it must indicate
                                             * the EtherChannel for which
                                             * a LACPDU is intended
                                             */
} ieee8023ad_aggregator_t;

/*
 * Interface configured over etherchannel or
 * any container device over etherchannel
 */
typedef struct ethchan_if
{
    struct ifnet *ifp;
    struct ethchan_if *next;
} ethchan_if_t;


/* Included in an ethchan_team_info element.  Has information for each
 * connection between EtherChannel and a remote host
 */
typedef struct ethchan_mac_ip
{
    uint32_t               time_to_live;    /* Number of minutes until node will be deleted */
    u_char                 host_mac[6];     /* MAC of the remote host */
    u_char                 host_ip[4];      /* IP address of the remote host */
    u_char                 ethchan_ip[4];   /* IP address of the EtherChannel */
    struct ethchan_mac_ip  *next_mac_ip;    /* Pointer to next node in the list */

} ethchan_mac_ip_t;

/* One of these will exist for each adapter under a teaming mode EtherChannel */
typedef struct ethchan_team_info
{
    ndd_t                  *nddp;           /* Pointer to the ndd for that EtherChannel adapter */
    ethchan_mac_ip_t       *mac_ip_node;    /* Pointer to the node(s) of the associated EtherChannel IP 
                                             * and remote host MAC and IP
                                             */
    uint32_t               node_count;      /* Number of nodes in this team_info struct */

} ethchan_team_info_t;

/* ----------------------------------------------------------------- */
/* EtherChannel control structure                                    */
/* ----------------------------------------------------------------- */

typedef struct ethchan_ccs
{
    struct ethchan_ccs *next_ccs;           /* Pointer to next EtherChannel
                                             * in the linked list
                                             */
    ndd_t *nddp_adapter[MAXIFPERCHAN];      /* Pointers to the ndd
                                             * structures of the adapters
                                             * of this channel
                                             */
    uint32_t seq_number;                    /* The sequence number the
                                             * ccs was configured with
                                             */
    uint32_t current_adapter;               /* Used for some modes to specify
                                             * the adapter to transmit on
                                             */
    uint32_t current_backup_adapter;        /* Used for some modes to specify
                                             * the backup adapter to transmit on
                                             */
    uint32_t current_recv_adapter;          /* Used for teaming mode 
                                             * to specify the adapter to
                                             * receive traffic on.
                                             */
    uint32_t ptp_adapter_channel;           /* Used for hw_ptp support 
                                             * to specify the adapter to
                                             * transmit on
                                             */
    ndd_t *ptp_adapter_ptr;                 /* Used for hw_ptp support 
                                             * to specify the adapter list
                                             * that ptp_adapter is a member of
                                             */
    uint32_t icmp_outstanding;              /* Number of pings packets
                                             * that have been sent but
                                             * whose reply has not yet
                                             * been received
                                             */
    ethchan_dds_t dds;                      /* Device Device Structure */
    ndd_t ndd;                              /* The copy of ndd structure
                                             * for this channel
                                             */
    ethchan_addr_t src_addr;                /* Source address used by
                                             * packets generated by the
                                             * channel (e.g. gratuitous
                                             * ARP packets)
                                             */
    ethchan_addr_t backup_src_addr;         /* Source address used by
                                             * packets generated by the
                                             * channel (e.g. gratuitous
                                             * ARP packets)
                                             */
    uint32_t unit;                          /* Number associated with
                                             * the interface
                                             */
    ethchan_if_t *if_list;                  /* List of interfaces configured
                                             * over etherchannel
                                             */
    ethchan_dev_t dev;                      /* Device control area */

    ndd_t *nddp_backup_adapter[MAXIFPERCHAN];/* Pointers to the ndd
                                             * structures of the backup adapters
                                             * of this channel
                                             */
    uint32_t flags;                         /* State flags for the channel
                                             * (see below for flags)
                                             */
    uint32_t no_of_initialized_adapters;    /* The number of adapters
                                             * whose link status we have
                                             * learned every time the
                                             * channel is opened: the
                                             * backup adapters are counted
                                             * in these calculations
                                             */
    uint32_t failure_reason;                /* The reason why the
                                             * channel failed over: may be
                                             * ECH_CHANNEL_FAILURE or
                                             * ECH_PING_FAILURE
                                             */
    uint32_t failure_code;                  /* Code for failure reason */
    ieee8023ad_aggregator_t aggregator;     /* Contains information
                                             * pertaining to the
                                             * aggregator for this link
                                             * aggregation
                                             */
    ent_genstats_t  statistics;             /* Holds the statistics
                                             * for the EtherChannel
                                             */
    ndd_t *nddp_address_owner;              /* Adapter where we got the
                                             * EtherChannel's MAC from
                                             */
    ndd_t *nddp_backup_address_owner;       /* Adapter where we got the
                                             * backup EtherChannel's MAC from
                                             */
    ethchan_addr_t adapter_addresses[MAXIFPERCHAN];/* Original MAC addresses
                                             * for adapters in the main
                                             * channel
                                             */
    ethchan_addr_t adapter_backup_addresses[MAXIFPERCHAN];/* Original MAC
                                             * addresses for adapters in the
                                             * backup channel
                                             */
    boolean_t swap_flag;                    /* Flag to swap channel */
    boolean_t ethchan_fail_flag;            /* Flag to log Etherchannel
                                             * recovery
                                             */
    boolean_t state_change;                 /* state change notification
                                             * event
                                             */
    caddr_t ndd_backup_physaddr;            /* Pointer to current
                                             * mac address for the backup
                                             * channel
                                             */
    ns_com_status_t status_filter;          /* Filter for nd_status changes */
    ns_statuser_t status_user;              /* user status block */
    ethchan_team_info_t team_info[MAXIFPERCHAN];/* One team_info structure
                                             * for each adapter under
                                             * a teaming mode EtherChannel
                                             */
    ethchan_mac_ip_t *removed_nodes;        /* List of mac_ip_data nodes
                                             *to be rebalanced
                                             */
    int32_t total_nodes;                    /* Total number of mac_ip_data nodes
                                             * in all team_info structures
                                             */
} ethchan_ccs_t;

/* These flags are used for masking the "flags" member of "ethchan_ccs" */

/* Set when all the primary adapters have failed and the backup adapter is
 * being used
 */
#define ETHCH_BACKUP_IS_ACTIVE          0x0001

/* Set when the channel has learned of the link status of all the adapters
 * after it is opened
 */
#define ETHCH_CHANNEL_IS_INITIALIZED    0x0002

/* Set when the channel has been configured with an IP address */
#define ETHCH_INTERFACE_IS_CONFIGURED   0x0004

/* Set when a recovery from backup to primary is pending */
#define ETHCH_RECOVERY_IS_PENDING       0x0008

/* Set when a failover from primary to backup is pending */
#define ETHCH_FAILOVER_IS_PENDING       0x0010

/* Set when a failover is due to ping failure (if clear, failover was due
 * to link failure); used to determine what type of logging should be
 * used when a failure is pending
 */
#define ETHCH_PING_FAILURE_FAILOVER     0x0020

/* Set when only internally-generated packets (like LACPDUs) should be traced:
 * used when the EtherChannel is in a container device that is already tracing
 * packets, so the EtherChannel should NOT trace them again in its output
 * routine
 */
#define ETHCH_INTERNAL_TRACE_ONLY       0x0040

/* State whether an EtherChannel with a backup adapter should recover
 * automatically after a failover when at least one of the main adapters
 * recovers; it is set by default
 */
#define ETHCH_AUTOMATIC_RECOVERY        0x0080

/* State whether an EtherChannel should perform delayed recovery to
 * improve failover and recovery times
 */
#define ETHCH_DELAYED_RECOVERY          0x0100

/* State whether an EtherChannel should perform lossless failover to
 * prevent packet loss when doing ping failovers
 */
#define ETHCH_LOSSLESS_FAILOVER         0x0200

/* State whether the backup adapter should retain its MAC and then primary
 * and backup MACs are swapped during failover.
 */
#define ETHCH_MAC_SWAP                  0x0400

/* Set when an EtherChannel is closing */
#define ETHCH_CLOSE_IS_PENDING          0x1000

/* Command passed to "ieee8023ad_init()" to configure IEEE 802.3ad */
#define IEEE_8023AD_CONFIGURE_CMD       0

/* Command passed to "ieee8023ad_init()" to unconfigure IEEE 802.3ad */
#define IEEE_8023AD_UNCONFIGURE_CMD     1

/* The number of seconds between sending LACPDUs periodically for long interval */
#define IEEE_8023AD_LONG_TIMEOUT        30

/* The number of seconds after which LACPDU is considered expired when LACP
 * interval is long. LACPDU must be received within this time period, otherwise
 * LACPDU is considered expired.
 */
#define IEEE_8023AD_LACP_EXPIRE_LONG_TIMEOUT    3 * IEEE_8023AD_LONG_TIMEOUT

/* The number of seconds between sending LACPDUs periodically for short interval */
#define IEEE_8023AD_SHORT_TIMEOUT       1

/* The number of seconds after which LACPDU is considered expired when LACP
 * interval is short. LACPDU must be received within this time period, otherwise
 * LACPDU is considered expired.
 */
#define IEEE_8023AD_LACP_EXPIRE_SHORT_TIMEOUT   3 * IEEE_8023AD_SHORT_TIMEOUT

/* The MAC address of the Slow Protocols Multicast group, which
 * is where LACPDUs are sent (01-80-C2-00-00-02)
 */
#define SLOW_PROTOCOLS_MULTICAST_ADDRESS {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02}

/* The Ethertype value of LACPDUs */
#define IEEE_8023AD_ETHERTYPE           0x8809

/* The value of the system priority of this system */
#define IEEE_8023AD_SYSTEM_PRIORITY     0x8000

/* The value of the operational key for all adapters */
#define IEEE_8023AD_OPERATIONAL_KEY     0xBEEF

/* The value of the port priority for all the ports */
#define IEEE_8023AD_PORT_PRIORITY       0x80

/* The value of the maximum delay between when a packet is received and
 * it is sent to the collector
 */
#define IEEE_8023AD_COLLECTOR_MAX_DELAY 0x8000

/* These constants are used in the construction of LACPDUs */
#define IEEE_8023AD_LACPDU_SUBTYPE                      0x01
#define IEEE_8023AD_LACPDU_VERSION                      0x01
#define IEEE_8023AD_LACPDU_ACTOR_TLV_TYPE               0x01
#define IEEE_8023AD_LACPDU_ACTOR_INFORMATION_LENGTH     0x14
#define IEEE_8023AD_LACPDU_PARTNER_TLV_TYPE             0x02
#define IEEE_8023AD_LACPDU_PARTNER_INFORMATION_LENGTH   0x14
#define IEEE_8023AD_LACPDU_COLLECTOR_TLV_TYPE           0x03
#define IEEE_8023AD_LACPDU_COLLECTOR_INFORMATION_LENGTH 0x10

/* These constants are used in the construction of marker PDUs */
#define IEEE_8023AD_MARKER_PDU_SUBTYPE                  0x02
#define IEEE_8023AD_MARKER_INFORMATION_TYPE             0x01
#define IEEE_8023AD_MARKER_RESPONSE_INFORMATION_TYPE    0x02

/* These flags are used for masking the "actor_state" and "partner_state"
 * fields of LACPDUs
 */
#define IEEE_8023AD_LACP_ACTIVITY       0x01
#define IEEE_8023AD_LACP_TIMEOUT        0x02
#define IEEE_8023AD_AGGREGATION         0x04
#define IEEE_8023AD_SYNCHRONIZATION     0x08
#define IEEE_8023AD_COLLECTING          0x10
#define IEEE_8023AD_DISTRIBUTING        0x20
#define IEEE_8023AD_DEFAULTED           0x40
#define IEEE_8023AD_EXPIRED             0x80

/* These values indicate the status of the link aggregation: its values
 * are set in ethchan_recalculate_status() and are queried by the
 * GET_ALL_STATS ioctl so the status of the aggregation can be
 * printed by the "entstat.ethchan" command
 */
#define IEEE_8023AD_STATUS_INACTIVE     0x00
#define IEEE_8023AD_STATUS_NEGOTIATING  0x01
#define IEEE_8023AD_STATUS_AGGREGATED   0x02
#define IEEE_8023AD_STATUS_FAILED       0x03

/* If adapter's ndd_2_flags NDD_2_VIRTUAL_PORT is set, VF mode enabled,
 * use NDD_2_PHYS_LINK_UP flag to determine if adapter link status is up/down.
 * else use NDD_RUNNING flag to determine if adapter link status is up/down.
 */
#define ADAPTER_LINK_STATUS(nddp) \
    ((nddp != NULL) ? \
        ((((ndd_t *)(nddp))->ndd_2_flags & NDD_2_VIRTUAL_PORT) ? \
        (((ndd_t *)(nddp))->ndd_2_flags & NDD_2_PHYS_LINK_UP):  \
        (((ndd_t *)(nddp))->ndd_flags & NDD_RUNNING)) : FALSE)

/*These values are used by EtherChannel teaming mode*/
#define TEAM_LINK_DOWN       (0)
#define TEAM_LINK_UP         (1)
#define TEAM_ADAPTER_REMOVED (2)
#define TEAM_ADAPTER_ADDED   (3)

typedef struct ethchan_trc
{
    uint32_t        res[3],         /* Reserved */
                    next,           /* Next index to put trace data in
                                     * the table
                                     */
                    res1,
                    res2,
                    res3;
    uint32long64_t  table[ETHCHAN_TRACE_SIZE];
} ethchan_trc_t;

typedef struct ethchan_tbl
{
    lock_t          table_lock;
    uint32_t        ccs_cnt;        /* Number of channels we have */
    uint32_t        open_cnt;       /* Count of active opens */
    ethchan_ccs_t   *p_ccs;         /* CCS pointer for each channel */
    Simple_lock     trace_lock;     /* Locks internal trace table */
    ethchan_trc_t   trace;          /* Internal trace table */
    Complex_lock    dd_clock;       /* The lock for the open/close sync */
} ethchan_tbl_t;

typedef struct ech_icmp
{
    struct  ip ip;
    struct  icmp icmp;
} ech_icmp_t;

typedef struct ech_icmp6
{
    struct  ipv6 ip6;
    struct  icmpv6 icmp6;
} ech_icmp6_t;

/* Structure representing an Ethernet header containing a VLAN tag */
typedef struct ethchan_vlan_hdr
{
    struct          ether_header;
    ushort_t        vlan_id;
    ushort_t        actual_ether_type;
} ethchan_vlan_hdr_t;

typedef struct ethchan_proc_param
{
    pid_t pid;
    tid_t wait_td;
    boolean_t done;
} ethchan_proc_param_t;

ethchan_proc_param_t    ethchan_proc_params;
uint32_t                ethchan_proc_lintr;

/* Macros for defining and using read/write locks */

/* Initialization of the read/write lock */
#define ETHCHAN_LOCKINIT()                                              \
{                                                                       \
    lock_alloc (&(p_ccs->dev.ethchan_lock.rw_lock), LOCK_ALLOC_PIN,     \
            XETHCHAN_DD_LOCK, -1);                                      \
    drw_lock_init (&(p_ccs->dev.ethchan_lock.rw_lock));                 \
}


/* Simple lock for new EtherChannel process */
Simple_lock             ethchan_proc_lock;

/* Initialization for ethchan_proc_lock */
#define ETHCHAN_PROC_LOCKINIT()                                         \
{                                                                       \
    lock_alloc (&ethchan_proc_lock, LOCK_ALLOC_PIN,                     \
            XETHCHAN_DD_LOCK, -1);                                      \
                                                                        \
    simple_lock_init (&ethchan_proc_lock);                              \
}

#define ETHCHAN_PROC_LOCK_FREE()                                        \
    lock_free (&ethchan_proc_lock);

#define ETHCHAN_PROC_LOCK()                                             \
    ethchan_proc_lintr = disable_lock(PL_IMP, &ethchan_proc_lock);

#define ETHCHAN_PROC_UNLOCK()                                           \
    unlock_enable(ethchan_proc_lintr, &ethchan_proc_lock);

/* Initialization of link lock */
#define ETHCHAN_LINK_LOCKINIT()                                         \
{                                                                       \
    lock_alloc (&p_ccs->dev.link_lock, LOCK_ALLOC_PIN,                  \
            XETHCHAN_DD_LOCK, -1);                                      \
                                                                        \
    simple_lock_init (&p_ccs->dev.link_lock);                           \
}

/* Macros for locking and unlocking link status */
#define ETHCHAN_LINK_LOCK()                                             \
    simple_lock (&p_ccs->dev.link_lock);

#define ETHCHAN_LINK_UNLOCK()                                           \
    simple_unlock (&p_ccs->dev.link_lock);

#define ETHCHAN_LINK_LOCK_FREE()                                        \
    lock_free (&p_ccs->dev.link_lock);

/* Initialization of the filter lock */
#define ETHCHAN_FILTER_LOCKINIT()                                       \
{                                                                       \
    lock_alloc (&p_ccs->dev.filter_lock, LOCK_ALLOC_PIN,                \
            XETHCHAN_DD_LOCK, -1);                                      \
    \
    simple_lock_init (&p_ccs->dev.filter_lock);                         \
}

/* Macros for locking and unlocking filters for add and delete */
#define ETHCHAN_FILTER_LOCK()                                           \
    simple_lock (&p_ccs->dev.filter_lock);

#define ETHCHAN_FILTER_UNLOCK()                                         \
    simple_unlock (&p_ccs->dev.filter_lock);

#define ETHCHAN_FILTER_LOCK_FREE()                                      \
    lock_free (&p_ccs->dev.filter_lock);

/* Declaration of local variables for storing interrupt priorities */
#define ETHCHAN_LOCK_DECL()                                             \
    int     _writepri

/* Macros for locking and unlocking exclusive disabled write access */
#define DRW_ETHCHAN_WRITE_LOCK()                                        \
    do {                                                                \
        (_writepri) = i_disable (PL_IMP);                               \
        drw_lock_write (&((p_ccs)->dev.ethchan_lock.rw_lock));          \
    } while (0)

#define DRW_ETHCHAN_WRITE_UNLOCK()                                      \
    do {                                                                \
        drw_lock_done (&((p_ccs)->dev.ethchan_lock.rw_lock));           \
        i_enable (_writepri);                                           \
    } while (0)

/* Macros for locking and unlocking shared disabled read locks */
#define DRW_ETHCHAN_READ_LOCK()                                         \
    do {                                                                \
        (_writepri) = i_disable (PL_IMP);                               \
        drw_lock_read (&((p_ccs)->dev.ethchan_lock.rw_lock));           \
    } while (0)

#define DRW_ETHCHAN_READ_UNLOCK()                                       \
    do {                                                                \
        drw_lock_done (&((p_ccs)->dev.ethchan_lock.rw_lock));           \
        i_enable (_writepri);                                           \
    } while (0)

/* We define the version of disabled write lock.
 * This disabled write lock will be released if dr_refcnt is not 0.
 */
#define ETHCHAN_WRITE_LOCK()                                            \
{                                                                       \
    DRW_ETHCHAN_WRITE_LOCK ();                                          \
    {                                                                   \
        volatile int32_t *myvalptr = &((p_ccs)->dev.ethchan_lock.dr_refcnt);\
        while (*myvalptr)                                               \
        {                                                               \
            DRW_ETHCHAN_WRITE_UNLOCK ();                                \
            DRW_ETHCHAN_WRITE_LOCK ();                                  \
        }                                                               \
    }                                                                   \
}

#define ETHCHAN_WRITE_UNLOCK()                                          \
    DRW_ETHCHAN_WRITE_UNLOCK ();

/* We define the version of read locks that interrupt is enabled after
 * dynamic operation reference count is updated.
 */
#define ETHCHAN_READ_LOCK()                                             \
    do {                                                                \
        DRW_ETHCHAN_WRITE_LOCK ();                                      \
        (p_ccs)->dev.ethchan_lock.dr_refcnt++;                          \
        DRW_ETHCHAN_WRITE_UNLOCK ();                                    \
    } while (0)

#define ETHCHAN_READ_UNLOCK()                                           \
    do {                                                                \
        DRW_ETHCHAN_WRITE_LOCK ();                                      \
        (p_ccs)->dev.ethchan_lock.dr_refcnt--;                          \
        DRW_ETHCHAN_WRITE_UNLOCK ();                                    \
    } while (0)


/* Macro for going from an exclusive write lock to a shared read lock */
#define ETHCHAN_WRITE_TO_READ_LOCK()                                    \
    do {                                                                \
        ETHCHAN_WRITE_UNLOCK ();                                        \
        ETHCHAN_READ_LOCK ();                                           \
    } while (0)

/* Macro for going from a shared read lock to an exclusive write lock */
#define ETHCHAN_READ_TO_WRITE_LOCK()                                    \
    do {                                                                \
        ETHCHAN_READ_UNLOCK ();                                         \
        ETHCHAN_WRITE_LOCK ();                                          \
    } while (0)

/* We will use the "ndd_reserved" field in the "ndd" structure to store
 * a pointer to the EtherChannel to which each adapter belongs. We use
 * this pointer to implement "delayed recovery": we do not recover to the
 * main channel until we know for sure its port has been initalized and it
 * can receive packets.
 * We cannot use the "ndd_ptr" field because that is already in use by
 * the Shared Ethernet Adapter (SEA), and an EtherChannel could be defined
 * within a SEA and we do not want to overwrite this field. Thus, we will
 * use the "ndd_reserved" field in the "ndd" structure: specifically, we will
 * use the 14th word (and optionally the 15th) of the field to store the
 * pointer to the EtherChannel to which the adapter belongs (32-bit
 * architectures will only need word 14, but 64-bit architectures will take
 * up words 14 and 15).
 * We define these macros to make the code more readable.
 */

/* This macro is used to read the stored EtherChannel pointer into the
 * the specified variable (we cast it to an EtherChannel CCS structure)
 */
#define ETHCHAN_POINTER_READ(variable,nddp)                             \
{                                                                       \
    variable = (ethchan_ccs_t *)nddp->ndd_parent_nddp;                  \
}

/* This macro is used to store the EtherChannel pointer into the
 * "ndd.ndd_reserved" field
 */
#define ETHCHAN_POINTER_STORE(nddp,value)                               \
{                                                                       \
    nddp->ndd_parent_nddp = (caddr_t) value;                            \
}

/* This macro is used to set the receive function pointer in an adapter */
#define ETHCHAN_SET_RECEIVE_FUNC(nddp,new_func)                         \
{                                                                       \
    nddp->nd_receive = new_func;                                        \
}

/* Macros for debug and error tracing */
#define ETHCHAN_XMIT    ((HKWD_ETHCHAN_XMIT  << 20) | HKTY_GT | 4)
#define ETHCHAN_OTHER   ((HKWD_ETHCHAN_OTHER << 20) | HKTY_GT | 4)

#define ETHCHAN_ETRACE(tag, a1, a2, a3)                                 \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_DETAIL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_MINIMAL, RAS_MEM_PRIV,             \
            ETHCHAN_OTHER, *(ulong *) (tag),                            \
            (ulong)(a1), (ulong)(a2), (ulong)(a3), 0);                  \
}
#define ETHCHAN_ETRACE_DETAIL(tag, a1, a2, a3)                          \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_DETAIL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_DETAIL, RAS_MEM_PRIV,              \
            ETHCHAN_OTHER, *(ulong *) (tag),                            \
            (ulong)(a1), (ulong)(a2), (ulong)(a3), 0);                  \
}

#define ETHCHAN_TRACE(tag, a1, a2, a3)                                  \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_DETAIL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_MINIMAL, RAS_MEM_PRIV,             \
            ETHCHAN_OTHER, *(ulong *) (tag),                            \
            (ulong) (a1), (ulong) (a2), (ulong) (a3), 0);               \
}

#define ETHCHAN_TTRACE(tag, a1, a2, a3)                                 \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_DETAIL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_MINIMAL, RAS_MEM_PRIV,             \
            ETHCHAN_XMIT, *(ulong *) (tag),                             \
            (ulong) (a1), (ulong) (a2), (ulong) (a3), 0);               \
}
#define ETHCHAN_TTRACE_DETAIL(tag, a1, a2, a3)                          \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_DETAIL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_DETAIL, RAS_MEM_PRIV,              \
            ETHCHAN_XMIT, *(ulong *) (tag),                             \
            (ulong) (a1), (ulong) (a2), (ulong) (a3), 0);               \
}

#define ETHCHAN_TRACE_NORMAL(tag, a1, a2, a3)                           \
{                                                                       \
    if (ERR_LEVEL(ras_ethchan_cbp) >= ERRCHECK_NORMAL) {                \
        ethchan_trace (tag, (uint32long64_t) a1,                        \
                (uint32long64_t) a2, (uint32long64_t) a3);              \
    }                                                                   \
    CT_HOOK5(ras_ethchan_cbp, CT_LVL_MINIMAL, RAS_MEM_PRIV,             \
            ETHCHAN_OTHER, *(ulong *) (tag),                            \
            (ulong) (a1), (ulong) (a2), (ulong) (a3), 0);               \
}
#endif  /* ! _H_ETHCHAN */