/* 1705, Sat 7 July 01 (NZT)

   FLOWHASH.H:  Data structures for AU Meter

   Copyright (C) 1992-2002 by Nevil Brownlee,
   CAIDA | University of Auckland */

/*
 * $Log: flowhash.h,v $
 * Revision 1.1.1.2.2.12  2002/02/23 01:57:30  nevil
 * Moving srl examples to examples/ directory.  Modified examples/Makefile.in
 *
 * Revision 1.1.1.2.2.10  2001/05/24 02:19:52  nevil
 * LfapMet implemented by Remco Poortinga.
 * MinPDUs implemented by Nevil.
 *
 * Revision 1.1.1.2.2.7  2000/08/08 19:44:52  nevil
 * 44b8 release
 *
 * Revision 1.1.1.2.2.5  2000/06/06 03:38:19  nevil
 * Combine NEW_ATR with TCP_ATR, various bug fixes
 *
 * Revision 1.1.1.2.2.2  2000/01/12 02:57:09  nevil
 * Implement 'packet pair matched' turnaroundtime distribution attributes.
 * Fix ASN-related bugs in NeTraMet, distribution-related bugs in fd_filter.
 *
 * Revision 1.1.1.2.2.1  1999/11/29 00:17:26  nevil
 * Make changes to support NetBSD on an Alpha (see version.history for details)
 *
 * Revision 1.1.1.2  1999/10/03 21:06:23  nevil
 * *** empty log message ***
 *
 * Revision 1.1.1.1.2.14  1999/09/24 04:09:46  nevil
 * *** empty log message ***
 *
 * Revision 1.1.1.1.2.13  1999/09/24 02:58:39  nevil
 * Polish up code to get rid of warning messages from Borland (DOS) compiler.
 * Make manager PeerAddress buffers NSAP_ADDR_LEN bytes long.
 * Add asn_lookup variable - only call FindSubnet if ruleset uses ASNs.
 *
 * Revision 1.1.1.1.2.12  1999/09/22 05:38:41  nevil
 * Improve code to work properly on 64-bit machines
 * - Add OS=ALPHA handling to configure.in
 * - Clean up the Alpha compiler warnings
 * - Change all the snmp-related code to use Bit32 instead of unsigned long
 *
 * Revision 1.1.1.1.2.11  1999/09/14 00:45:28  nevil
 * 4.3 Release ..
 *  - Implement -D option to run NeTraMet as a daemon
 *  - Tidy up the on-line help displays
 *
 * Revision 1.1.1.1.2.10  1999/05/26 02:41:39  nevil
 * Integrate V6 and ASN code into PC versions of the meter.
 * This required a rework of the makefiles, using @cflags.opt files
 * to provide a much longer command line to the Borland C compiler.
 *
 * Revision 1.1.1.1.2.9  1999/05/18 03:36:28  nevil
 * Implement IPv6 in NeTraMet, and its manager/collectors.
 * - This is controlled by the V6 #define
 * - NeTraMet recognises v6 packets and fishes through their extension
 *     headers until it finds the actual payload.
 * - NeMaC et al display v6 addresses in the fom specified by RFC 2373
 * - fd_util and fd_extract allow colons in addresses (for defining tags)
 *
 * Revision 1.1.1.1.2.8  1999/05/17 00:11:57  nevil
 * Fixed 'reuse of ruleset row' problem:
 *   When a ruleset row is destroyed, set_RowStatus calls free_rulespace()
 *   and recover_flows().  free_rulespace() zeroed its varibales in the
 *   ri[] row, but recover_flows() didn't (it should have zeroed
 *   ri_flow_chain).  This left ri_flow_chain pointing to a free flow,
 *   which cause problems if a manager tried to reuse this row for a
 *   new ruleset.  Fixed by zeroing all of the ri[] row. (Also commented
 *   out the zeroing code from free_rulesace).
 *
 * Revision 1.1.1.1.2.7  1999/02/16 00:10:53  nevil
 * Make sure globals are declared when TCP_ATR=0
 *
 * Revision 1.1.1.1.2.6  1999/02/15 21:24:08  nevil
 * Distribution file for 4.3b9
 *
 * Revision 1.1.1.1.2.4  1999/01/20 03:55:50  nevil
 * Implementation of TCP attributes, part 4
 *
 * Revision 1.1.1.1.2.3  1999/01/08 01:31:53  nevil
 * Implementation of TCP attributes, part 3
 *
 * Revision 1.1.1.1.2.2  1998/12/22 23:53:08  nevil
 * Implementation of TCP attributes, part 2
 *
 * Revision 1.1.1.1  1998/11/16 03:57:29  nevil
 * Import of NeTraMet 4.3b3
 *
 * Revision 1.1.1.1.2.2  1998/11/16 02:46:58  nevil
 * Implementation of TCP attributes, part 1
 *
 * Revision 1.1.1.1.2.1  1998/11/11 23:14:44  nevil
 * Only include malloc.h if we HAVE_MALLOC_H
 *
 * Revision 1.1.1.1  1998/10/28 20:31:27  nevil
 * Import of NeTraMet 4.3b1
 *
 * Revision 1.1.3.1.2.3  1998/10/27 04:09:03  nevil
 * Modified OCX defines for 'flat memory' testing for 32-bit DOS
 * meters.  Changed some data defines to allow p2primes[] comparisons
 * to work  properly for 16-bit DOD meter
 *
 * Revision 1.1.3.1.2.2  1998/10/19 22:32:45  nevil
 * Meter improvements, mostly arising from developments for the
 * OCxMON meter.  These are documented in notes_oc.txt
 *
 * Revision 1.1.3.1.2.1  1998/10/18 20:51:19  nevil
 * Added Nicolai's patches, some 'tidying up' of the source
 *
 * Revision 1.1.3.2  1998/10/14 04:53:22  nevil
 * Merge Nicolai's patches into 4.2.1 distribution
 *
 * Revision 1.3  1998/07/21 00:40:14  rtfm
 * Implement popto/poptoact actions for SRL
 *
 * Revision 1.2  1998/05/22 03:57:35  rtfm
 * Implement better hashing algorithm for flow and rule tables
 */

#ifndef EXTFLOW
#define EXTFLOW  extern
#define DECLARE  0
#define INIT(v)
#else
#define EXTFLOW
#define DECLARE  1
#define INIT(v)  = v
#endif

#ifndef MAX_SUBID
#include "asn1.h"
#endif

#define MXRTBLS     20  /* Max nbr of rule tables */
#define MXCLCTRS    20  /* Max nbr of Meter Readers */
#define MXMANAGERS  10  /* Max nbr of Managers */

#define RSTKSIZ     50  /* Max depth of rule matches stack */
#define ESTKSIZ     50  /* Max depth of rule gosub stack */
#define MXRHTSZ   3727  /* Max size for rule-group hash table */

#define MNCGRPSZ     5  /* Min nbr of rules in a compare group */
#define RCHUNKSZ   250  /* Rule hash size is a multiple of this */
#define RTSLOPSZ    20  /* Nbr of extra rules to add into rule tables */

#define NAMESZ      16  /* Chars in a name (rulesets, readers, managers) */

#if defined(__LARGE__)
#define FLOW_INDEX     1
#else
#define FLOW_INDEX     0
#endif

#if OCX_NTM || OC3_NTM || CR_DATA  /* High-speed (OCx) version.  Default maxima .. */
#define DFMXFLOWS    100000    /* Nbr of traffic flows */
#define MXMASKS          70    /* Nbrbr of (different) mask values */
#define DFMXRULES      2000    /* Nbr of rules (in all rulsets) */
#define DFMXSTRBLOCKS   500    /* Nbr of flows metering TCP streams */
#define DFMXSTREAMS    2000    /* Nbr of TCP streams */
#define DFMXDISTRIBS     20    /* Nbr of distributions */
#define DFMXDISTEVENTS   10    /* Nbr of events (times) for distributions */
#define DFMXPKTDATS    4000    /* Nbr of packets we hold data on */
#elif defined(__FLAT__)  /* 32-bit PC version */
#define DFMXFLOWS     10000 
#define MXMASKS          70
#define DFMXRULES      2000
#define DFMXSTRBLOCKS   500
#define DFMXSTREAMS   2000
#define DFMXDISTRIBS     20
#define DFMXDISTEVENTS   10
#define DFMXPKTDATS    4000
#elif defined(DOS)       /* 16-bit PC version */
#define DFMXFLOWS      2000 
#define MXMASKS          50
#define DFMXRULES      1000
#define DFMXSTRBLOCKS    20
#define DFMXSTREAMS     100
#define DFMXDISTRIBS      5
#define DFMXDISTEVENTS    5
#define DFMXPKTDATS     200
#else                    /* Unix version */
#define DFMXFLOWS     10000 
#define MXMASKS          70
#define DFMXRULES      2000
#define DFMXSTRBLOCKS   500
#define DFMXSTREAMS    2000
#define DFMXDISTRIBS    100
#define DFMXDISTEVENTS   20
#define DFMXPKTDATS    4000
#endif

EXTFLOW int trace_interval INIT(0);  /* Collection interval for trace file */
EXTFLOW const char *crl_info INIT("");  /* Null if can't read trace file */

EXTFLOW unsigned long last_t_sec INIT(0);
   /* Unix seconds from timestamp of last merged packet */


#if CR_DATA || DAG_DIRECT
#define CT_WAIT_RULES       0
#define CT_RULES_READY      1
#define CT_PROCESS_FLOWS    2
#define CT_WAIT_FLOWS_READ  3
#define CT_TRACE_EOF        4
#define CT_SHUTDOWN         5
EXTFLOW int trace_state INIT(CT_WAIT_RULES);  /* Interlock with NeMaC -T */
#endif

EXTFLOW struct flow **flow_ht;
EXTFLOW Bit32 fthashmod;
   /* Use a single hash table for all rulesets.  Nevil, 11 Sep 98 */
   
#if 1  /* v4 */
#define AT_DUMMY       0  /* Addr_type values */

#define AT_IP4         1  /* Address Family numbers */
#define AT_IP6         2
#define AT_CLNS        3
#define AT_OTHER       6  /* (includes all 802 media) */
#define AT_NOVELL     11
#define AT_ETHERTALK  12
#define AT_DECNET     13

#define AT_ETHERNET    7  /* ifType 'ethernet-like' [RFC1643] */
#define AT_TOKENRING   9  /* ifType IEEE802.5 */
#define AT_FDDI       15  /* ifType FDDI [RFC1285] */
#define AT_PPP        23  /* ifType ppp  [RFC1471] */
#define AT_ATM        37  /* ifType ATM */
#define AT_SONET      39  /* ifType SONET or SDH */
#define AT_AAL5       49  /* ifType AAL5 over ATM */

#if CR_DATA
#define AT_TRACE     255  /* CoralReef trace file */
#endif

#define MX_PROTOCOLS  AT_DECNET
#else /* v3 */
#define AT_DUMMY      1
#define AT_IP         2
#define AT_CLNS       3
#define AT_IDPR       4
#define AT_DECNET     5
#define AT_NOVELL     6
#define AT_ETHERTALK  7
#define AT_DETAIL     8
#define AT_OTHER     12
#endif

#define PT_ICMP       1  /* IP protocol types */
#define PT_TCP        6
#define PT_UDP       17
#define PT_GRE       47  /* RFC 1701/1702 */
#define PT_OSPF      89  /* RFC 1583 */
                         /* IPv6 Next Header values (RFC 2460) */
#define PT_6HOP       0  /* Hop-by-hop options */
#define PT_6ROUT     43  /* Routing (Type 0) */
#define PT_6FRAG     44  /* Fragment */
#define PT_6DEST     60  /* Destination options */
#define PT_6AH       51  /* Authentication (AH) RFC 2402 */
#define PT_6ESP      50  /* Encapsulating Security Payload (ESP) RFC 2406 */
#define PT_6ICMP     58  /* ICMPv6 */
#define PT_6NONH     59  /* No next header */

EXTFLOW int addr_len[]  /* Lengths for each address type (bytes) */
#if DECLARE
   = {
      PEER_ADDR_LEN,    /*  0 'Didn't save PeerType' or 'dummy' */
      IP4_ADDR_LEN,     /*  1 IP4 */
      IP6_ADDR_LEN,     /*  2 IP6 */
      NSAP_ADDR_LEN,    /*  3 CLNS */
      0,                /*  4 */
      0,                /*  5 */
      TRANS_ADDR_LEN,   /*  6 Other */
      0,                /*  7 */
      0,                /*  8 */
      0,                /*  9 */
      0,                /* 10 */
      IPX_ADDR_LEN,     /* 11 Novell IPX */
      ET_ADDR_LEN,      /* 12 EtherTalk */
      DN_ADDR_LEN       /* 13 DECnet */
      }
#endif
   ;

EXTFLOW int addr_len32[]  /* Lengths for each address type (32-bit words) */
#if DECLARE
   = {
      (PEER_ADDR_LEN+3)/4,    /*  0 'Didn't save PeerType' or 'dummy' */
      (IP4_ADDR_LEN+3)/4,     /*  1 IP4 */
      (IP6_ADDR_LEN+3)/4,     /*  2 IP6 */
      (NSAP_ADDR_LEN+3)/4,    /*  3 CLNS */
      0,                      /*  4 */
      0,                      /*  5 */
      (TRANS_ADDR_LEN+3)/4,   /*  6 Other */
      0,                      /*  7 */
      0,                      /*  8 */
      0,                      /*  9 */
      0,                      /* 10 */
      (IPX_ADDR_LEN+3)/4,     /* 11 Novell IPX */
      (ET_ADDR_LEN+3)/4,      /* 12 EtherTalk */
      (DN_ADDR_LEN+3)/4       /* 13 DECnet */
      }
#endif
   ;

EXTFLOW char *proto_names[]
#if DECLARE
   = {
      "",              /*  0 */
      "IPv4",          /*  1 IP4 */
#if V6
      "IPv6",          /*  2 IP6 */
#else
      "",              /*  2 IP6 */
#endif
#if CLNS
      "CLNS",          /*  3 CLNS */
#else
      "",              /*  3 CLNS */
#endif
      "",              /*  4 */

      "",              /*  5 */
      "Other",         /*  6 Other */
      "",              /*  7 */
      "",              /*  8 */
      "",              /*  9 */
      "",              /* 10 */
      "Novell IPX",    /* 11 Novell IPX */
      "EtherTalk",     /* 12 EtherTalk */
      "DECnet IV",     /* 13 DECnet */
      }
#endif
   ;

EXTFLOW int use_ip_length INIT(0);

EXTFLOW int proto_reqd[1+MX_PROTOCOLS];  /* 1 => protocol used by rules */
EXTFLOW int adj_reqd;  /* 1 => adjacent addresses used by rules */
#if NF_OCX_BGP
EXTFLOW int asn_lookup INIT(0);  /* 1 => ASNs used by rules */
#endif

EXTFLOW Bit32 mxdistribs, mxdistevents;

#if NEW_ATR
struct event {
   struct event *next;
   Bit32 t;
   int interval;
   struct distribution *dp;
   };

EXTFLOW struct event eventq
#if DECLARE
   = {NULL, 0L, 0, NULL}
#endif
   ;

EXTFLOW struct event *events,  /* Space for events */
   *free_events;
EXTFLOW Bit32 n_free_events INIT(0);

#define WNP_FTPDATA  20  /* Well-known tcp/udp port numbers */
#define WNP_FTP      21
#define WNP_TELNET   23
#define WNP_SMTP     25
#define WNP_DOMAIN   53
#define WNP_WWW      80
#define WNP_NNTP    119
#define WNP_NTP     123
#define WNP_SNMP    161

#define PP_NO_TEST        0  /* Packet-Pairs for TurnaroundTimes */
#define PP_ICMP_ECHO      1
#define PP_ICMP_TIMSTMP   2

#define PP_OTHER          7  /* Just build streams (for InterarrivalTimes) */

#define PP_UDP_DNS       11
#define PP_UDP_ECHO      12
#define PP_UDP_SNMP      13

#define PP_TCP         0xC0  /* (=192)  Low-order bits as follows .. */
#define PP_OK_SYNACK   0x01  /*   ->SYN,  <-SYN+ACK pairs */
#define PP_OK_SYNRST   0x02  /*   ->SYN,  <-SYN+RST pairs */

#define PP_OK_MULTI    0x08  /*   ->DATA, <-ACK for more than one packet */
#define PP_OK_SINGLE   0x10  /*   ->DATA, <-ACK for single packets */
#define PP_OK_INGROUP  0x20  /*   ->DATA, <-ACK for packets within a group */

struct peer_addrs {
   Bit8 SrcPeerAddr[PEER_ADDR_LEN], DestPeerAddr[PEER_ADDR_LEN];
   };
   
struct pktdata {
   struct pktdata *next;
   double ts;  /* Time (microseconds) meter saw the packet */
   Bit16 pkt_len;  /* Bytes (on the wire) in packet */
   Bit8 direction,  /* MFWD or MREV */
      pp_type;  /* Packet-Pair type (from defines above) */
   union {
      struct {
         struct peer_addrs pa;
         Bit16 ident;
         Bit16 sequence;
         } icmp;
      union {
         struct {
            struct peer_addrs pa;
            Bit16 ident;  /* Set by requestor */
   	    } dns;
         struct {
	    } snmp;
         } udp;
      struct {
         Bit32 ack,  /* TCP ACK for this packet */
	    exp_seq;  /* TCP SEQ + TCP data len */
         Bit16 d_len,  /* Nbr of TCP data bytes in packet */
            pkt_nbr;  /* Index of packet in stream */
/*	    send_win,  /* Window advertised in this pkt */
/*          recv_win;  /* Space in receiver window (from last ACK) */
         Bit8 flags;  /* TCP flags for this packet */
         } tcp;
      } pi;
   };

EXTFLOW struct pktdata *packet_data,   /* Space for packet data blocks */
   *free_pkt_dat;
EXTFLOW Bit32 n_free_pktdata INIT(0);

EXTFLOW Bit32
   PktsCreated INIT(0),
   PktsRecovered INIT(0);

#define DISTRIB_PARAM_LEN   6
#define MXBUCKETS     100
struct distribution {
   Bit32 counts[MXBUCKETS+1];
   Bit8 non_empty,  /* Sum of counts[] >= 1 */
      selector,  /* Attribute number */
      mask_params[DISTRIB_PARAM_LEN], value_params[DISTRIB_PARAM_LEN];

   double M;   /* Range, for transform() */
   Bit8 Transform, ScaleFactor; /* 'mask' parameters */
   Bit16 LowerLimit, UpperLimit;
   Bit8 Buckets, Parameter1;  /* 'value' parameters */
   Bit16 Parameter2, Parameter3;

   int n_values,  /* Number of points in 'dynamic' distribution */
      lowerlim, upperlim,  /* Specified by user */
      min_val, max_val;  /* Observed in data */

   int trainlength, last_was_in_train;  /* Experimental, May 01 */

   struct flow *fp;  /* Flow creating distrib */
   struct distribution *next;  /* Chain of distribs for the flow */
   struct distribution *nrate;  /* Chain of distribs for computing rates */
   };
#define DS_NULL     0  /* Distribution transform type values */
#define DS_LIN      1  /* Linear */
#define DS_LOG      2  /* Logarithmic */

/* "Dynamic" distributions:
  Collects actual values until trigger point reached,
  then sets lower and upper parameters from data.
  Data values (actual and buckets) are **not** SNMP counters.
  Instead they are cleared after being read. */
#define DS_DYN_REQ  4  /* Dynamic: request */
#define DS_DYN_PTS  5  /* Dynamic: values (Buckets = nbr of values) */
#define DS_DYN_BKT  6  /* Dynamic: bucket counts (limits set from data */

#define PP_Type       Parameter1  /* For To/From Turnaround (Bit8) */
#define RateInterval  Parameter1  /* For To/From Bit/PDU Rate (Bit8) */

                            /* TCP Size/Rate filter parameters .. */
#define SizeScale     Parameter1  /* Filter scale factor (Bit8) */
#define LowerSize     Parameter2  /* Ignore if <= Lower (Bit16) */
#define UpperSize     Parameter3  /* Ignore if > Upper (Bit16) */

EXTFLOW struct distribution *distribs,  /* Space for distributions */
   *free_distribs;
EXTFLOW Bit32 n_free_distribs INIT(0);

#endif  /* NEW_ATR */

EXTFLOW Bit32 mxstreams, mxstr_blocks, mxpktdatas;

#if NEW_ATR
#define ToFINseen    0x01
#define FromFINseen  0x02
#define BothFINseen  (FromFINseen | ToFINseen)
#define ToSYNseen    0x04
#define FromSYNseen  0x08
#define BothSYNseen  (FromSYNseen | ToSYNseen)
#define RSTseen      0x10

#define TCP_STREAM_TIMEOUT     200  /* 200 cs = 2s (FIN_WAIT) */
#define OTHER_STREAM_TIMEOUT  1000  /* 10s */

#define STO_MULTIPLIER  10;  /* Was 20 */

# if TCP_PKT_TRACE
# define TRACE_SZ  20

# define sess_Forward     0x40
# define sess_PktPrinted  0x80
/* Use flags_seen defines (above) for rest of s_flags byte */

struct trace_rec {
   Bit16 pkt_nbr;
   Bit16 time_int;
   Bit16 TCPlen;  /* MSB = 1 for 'to,' 0 for 'from' */
   Bit8 flags, s_flags;
   Bit32 Seq, maxSeq;
   };

struct sf_trace {
   double last_pkt_time;
   int pkt_nbr;
   int sf_trx;  /* Index of next trace record to fill */
   struct trace_rec tr[TRACE_SZ];
   };
# endif  /* TCP_PKT_TRACE */

struct stream_name {
#if QBYTE_PEER
   Bit32 SrcPeerAddr, DestPeerAddr;
#else
   Bit32 SrcPeerAddr[(PEER_ADDR_LEN+3)/4],
      DestPeerAddr[(PEER_ADDR_LEN+3)/4];
#endif
   Bit16
      SrcTransAddr,
      DestTransAddr;
#if WORDS_BIGENDIAN
   Bit16 rsv1;
   Bit8
      TransType, RuleSet;
#else
   Bit8
      TransType, RuleSet;
   Bit16 rsv1;
#endif
   };
   
struct stream {
   struct stream huge
      *next_hc,            /* Streams in a hash chain */
      /* Must be first item in structure to allow circular hash chains */
      *next_sp,            /* Streams for a flow, free list */
      *prev_sp;            /* Reverse stream chain for flow */

   double  /* Time (microseconds) of STREAM's last packet in each direction */
      LastToTime, LastFromTime,
      StrFirstTime;        /* First packet time in micrtoseconds */

   struct pktdata *pq;     /* Recent packets for this stream */
   Bit16 pkt_nbr;          /* Nbr of pkts seen for this stream */
   Bit16 pq_len;           /* Packets in the queue */
   Bit16 mx_pq_len;        /* Max allowed packets in queue */

   Bit8 ToSeen, FromSeen;   /* Set when 'to' or 'from' packet seen */

   Bit8  /* TCP things */
      flags_seen, terminating,
      ToSeq_seen, FromSeq_seen,
      ToAck_seen, FromAck_seen;
   Bit8 rsv1, rsv2;

   Bit32
      ToLastSeq, FromLastSeq,
      ToLastAck, FromLastAck,
      ToSeqOctets, FromSeqOctets,
      ToAckOctets, FromAckOctets;

   Bit32  /* Flow things */
      ToPDUs, FromPDUs,      /* We hope that these won't wrap, at */
      ToOctets, FromOctets;  /* least not for streams within a flow */
   Bit32     /* uptime() when first and last packets seen for stream */
      FirstTime, LastTime;
/*      FromWindow, ToWindow; */
   struct flow *flowp;

# if TCP_TRACE
   int sf_nbr;
# endif
# if TCP_PKT_TRACE
   struct sf_trace sft;
# endif

   struct stream_name sfn;  /* IP address and port pairs */
      /* Have this last so can zero everything else */
   };

EXTFLOW struct stream *sfa,  /* Space for streams */
   *free_streams;
EXTFLOW Bit32 n_free_streams INIT(0);

EXTFLOW struct stream **sfht;  /* Stream hash table */
EXTFLOW Bit32 sfhashmod;

EXTFLOW Bit32
   StreamsCreated INIT(0),
   StreamsRecovered INIT(0);

struct stream_data {  /* For all IP flows with stream attributes */
   struct stream_data *next;  /* stream_data free list */
   struct stream huge
      *sq,   /* Streams for this flow, increasing FirstTime order */
      *sq_tail;  /* Tail of stream queue */
   double U;  /* Packets counted as lost after U centiseconds */
   Bit32 n_streams,  /* Total nbr of streams seen */
      terminating_streams,
      active_streams, mx_active_streams,
      ToTCPDecrSeq, FromTCPDecrSeq,
      ToLostPDUs, FromLostPDUs,  /* Detected via PP turnaround,
                       or by timeouts or max pq_len restrictions */
      ToPQOverflows, FromPQOverflows;  /* max pq_len restrictions PQOF */
   counter64
      ToTCPSeqOctets, FromTCPSeqOctets,  /* Last-First Seq nbrs */
      ToTCPAckOctets, FromTCPAckOctets,  /* Last-First Ack nbrs */
      ToTCPLenOctets, FromTCPLenOctets;  /* Sum of TCP data lengths */

   double  /* Time (microseconds) of FLOW's last packet in each direction */
      LastToTime, LastFromTime;
   Bit8 ToSeen, FromSeen;  /* Set when 'to' or 'from' packet seen */

   Bit8 pp_match_reqd;    /* Distrib list includes a turnaround attribute */
   };

EXTFLOW struct stream_data *strb,  /* Space for stream_data blocks */
   *free_str_blocks;
EXTFLOW Bit32 n_free_str_blocks INIT(0);
#endif  /* NEW_ATR */

#if NF_OCX_BGP
EXTFLOW int use_owner_asns INIT(0);
#endif

struct key {
   union address PeerAddress;
   Bit32 AdjAddr_ms4;  Bit16 AdjAddr_ls2;  
   Bit16 TransAddress;
   Bit8 PeerMaskVal, TransMaskVal, AdjMaskVal, rsv1;
   Bit8 AdjAddrType, Interface, Class, Kind;
#if NF_ASN_ATT
   Bit16 RouteASN;
   Bit8 ASNMaskVal, RoutePrefix;
#endif
   };

struct flow_key {
   struct key Low, High;
   Bit8 PeerAddrType, TransAddrType;
   Bit8 FlowClass, FlowKind, MeterId, DSCodePoint;
   Bit8 rsv1, rsv2;  /* Bit32-align keys */
   };

struct flow {
   struct flow *ht_next;  /* For hash chains */
   /* Must be first item in structure to allow circular hash chains */
   Bit32 rs_next;  /* For ruleset chains */

   struct flow_key fk;

   counter64 UpOctets,UpPDUs, DownOctets,DownPDUs;
   Bit32 FirstTime,LastTime;
#if NF_CISCO_DATA
   Bit32 ntm_LastTime;
   /* Needed for TimeFiltering and garbage collecting */
#else
#define ntm_LastTime  LastTime
#endif
   Bit8 FlowRuleSet;  /* (1-org) index of set which created this flow */
      /* Active flows are linked into hash chains,
         i.e. they have non-null 'next' fields */

#if NEW_ATR
   Bit32 distrib_bits;  /* One bit set for each attribute counted */
   struct distribution *distrib_list;

   counter64  /* For short-term bit rates */
      LastUpOctets,LastUpPDUs, LastDownOctets,LastDownPDUs;

   struct stream_data *stdata;  /* Each stream has its own packet queue */
#endif
   };

EXTFLOW Bit32 nflows,  /* Nbr of flows in use */
   mxflows;  /* Max nbr of flows (i.e. size of flow table) */
EXTFLOW struct flow *fa;  /* Space for flows */
#define flow_nbr(f)  ((f-fa) + 1)  /* Compiler does the /sizeof() ! */

EXTFLOW Bit32  /* Queue of free flows */
   free_flow_head, free_flow_tail;

/* States of entries in flow table:
      Idle      = May be used for a new flow
      Inactive  = Has been read, may be garbage collected
      Orphan    = Not in hash table, (not running), waiting to be read
      Active    = Ruleset running, waiting to be read */

#define flow_orphan(fp) (fp->ht_next == NULL)
#define mark_orphan(fp)  fp->ht_next = NULL

#if FLOW_INDEX
EXTFLOW struct flow **flow_ix;  /* The flow table */
   /* Flow 1 was a dummy for the Create and Active tables in v3 */

#define flow_idle(n)    (flow_ix[n-1] == NULL)
#define mark_idle(n)    flow_ix[n-1] = NULL

#else  /* !FLOW_INDEX */

#define flow_idle(n)    (fa[n-1].FlowRuleSet == 0)
void mark_idle(Bit32 n);

#endif

EXTFLOW Bit32 empty_ix;  /* Last flow number used by number_flow */

EXTFLOW Bit32 gcf_ix;  /* Next possible flow for garbage collector */

EXTFLOW int  /* Parameters for garbage collector */
   gc_interval INIT(10),  /* Seconds between calls */
   gc_f INIT(4),  /* Flow indexes to test each call */
   already_complained INIT(0);  /* True if GC knows there are no free flows */

EXTFLOW Bit32 GarbageCollectTime INIT(0),
   /* OK to recover flows with LastTime greater than this */
   FlowsCreated INIT(0),
   FlowsRecovered INIT(0);

struct MaskVal {
   union address Val[RULE_ADDR_LEN];
   };
EXTFLOW struct MaskVal Masks[MXMASKS]
#if DECLARE
   = {
# if CLNS
         {  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
          255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
# elif V6 || FULL_IPX
         {  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
         {255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
# else  /* v4 */
         {0,0,0,0,0,0},   {255,0,0,0,0,0}
# endif
      }
#endif
   ;
EXTFLOW int n_masks INIT(2);

struct rule {
   union address RuleMatchedValue;  /* Rule's MIB variables */
   Bit8   RuleSelector;
   Bit8   RuleMaskVal;  /* Index to Masks[] */
   Bit16  RuleJumpIndex;
   Bit8   RuleAction;

   Bit8   push_rule;  /* For build_search_key() */
   Bit32  hash_tbl_index;  /* For match: 0 => simple compare */
   Bit32  hash_link;
   };

EXTFLOW struct rule *rule_space;
   /* Single space for all rulesets.  Nevil, 14 Sep 98 */
EXTFLOW Bit32 mxrules, inuse_rules;

EXTFLOW Bit16 *rule_hash_space;
   /* Single space for all rulesets.  Nevil, 16 Sep 98 */
EXTFLOW Bit32 mxrulehash, inuse_rule_hash;

EXTFLOW int tbl_size[5]  /*  Meter info table sizes */
   /* 1.1 = rule, 1.2 = interface, 1.3 = reader, 1.4 = manager table */
#if DECLARE
   = {0, MXRTBLS, 1, MXCLCTRS, MXMANAGERS}
#endif
   ;
   
struct rtinf_rec {  /* v4 */
   Bit16 ri_Size;
   char ri_Owner[NAMESZ+1];  /* +1 for terminating null */
   Bit32 ri_TimeStamp;
   int ri_Status;
   char ri_Name[NAMESZ+1];
   Bit32 ri_FlowRecords;

   Bit32 ri_flow_chain;  /* First flow in chain (1-org) */
   Bit32 ri_rule_offset;
   struct rule *ri_rule_table;
   int ri_rule_hash_size;
   Bit32 ri_rule_hash_offset;
   Bit16 *ri_rule_hash;
   int ri_running;
   int next_running_rt;  /* (1-org) index of next running ruleset */
   int ri_old_status;
   Bit32 ri_gc_time;
   };
EXTFLOW struct rtinf_rec ri[MXRTBLS];

EXTFLOW int running_rts INIT(0);  /* Chain of running rulesets */

EXTFLOW Bit16 c_rtx;  /* Rule table index of current rule table */
EXTFLOW struct rule *c_rt;  /* Current Rule Table */
EXTFLOW Bit16 c_rsz;  /* Nbr of rules in current rule table */
EXTFLOW struct hash_tbl *c_ht;  /* Current Hash Table */
EXTFLOW Bit16 *c_rht;  /* Current Rule Hash Table */

struct rule_hash_tbl {
   Bit16 group_last;  /* Nbr of last rule in group */
   Bit16 hashmod;  /* Group hash table size */
   Bit16 hash_ent[1];
   };

#define RA_IGNORE        1  /* RuleAction values */
#define RA_RETRY         2
#define RA_COUNT         3
#define RA_COUNTPKT      4
#define RA_RETURN        5
#define RA_GOSUB         6
#define RA_GOSUBACT      7
#define RA_ASSIGN        8
#define RA_ASSIGNACT     9
#define RA_GOTO         10
#define RA_GOTOACT      11
#define RA_PUSHTO       12
#define RA_PUSHTOACT    13
#define RA_PUSHPKTTO    14
#define RA_PUSHPKTTOACT 15
#define RA_POPTO        16
#define RA_POPTOACT     17


#define RS_NULL                 0  /* Rule Selector dummy value */

#define FTFLOWINDEX		1  /* Flow table attribute values */
#define FTFLOWTIMEMARK          2  /* Added in 'Experimental RTFM' MIB */
                                   /*   Following attribs move up by 1 */
#define FTFLOWSTATUS		3

#define FTLOWINTERFACE          4
#define FTLOWADJACENTTYPE       5
#define FTLOWADJACENTADDRESS    6
#define FTLOWADJACENTMASK       7
#define FTLOWPEERTYPE		8
#define FTLOWPEERADDRESS	9
#define FTLOWPEERMASK	       10
#define FTLOWTRANSTYPE         11
#define FTLOWTRANSADDRESS      12
#define FTLOWTRANSMASK         13

#define FTHIINTERFACE          14
#define FTHIADJACENTTYPE       15
#define FTHIADJACENTADDRESS    16
#define FTHIADJACENTMASK       17
#define FTHIPEERTYPE	       18
#define FTHIPEERADDRESS	       19
#define FTHIPEERMASK	       20
#define FTHITRANSTYPE          21
#define FTHITRANSADDRESS       22
#define FTHITRANSMASK          23

#define FTPDUSCALE             24
#define FTOCTETSCALE           25
#define FTRULESET              26

#define FTUPOCTETS	       27
#define FTUPPDUS	       28
#define FTDOWNOCTETS	       29
#define FTDOWNPDUS	       30
#define FTFIRSTTIME	       31
#define FTLASTTIME	       32

#define FTLOWSUBSCRIBERID      33
#define FTHISUBSCRIBERID       34
#define FTSESSIONID            35

#define FTSOURCECLASS	       36
#define FTDESTCLASS            37
#define FTFLOWCLASS	       38
#define FTSOURCEKIND 	       39
#define FTDESTKIND 	       40
#define FTFLOWKIND 	       41


#define FTDSCODEPOINT         118
#if !NEW_ATR
#define N_OLD_ATRS     (FTFLOWKIND + 1)  /* 1 DS attribute */
#define LASTATTRIB      FTHIDSCODEPOINT   /* May be redefined below */
#else
#define FTTOLOSTPDUS          121
#define FTFROMLOSTPDUS        122
#define FTTOPQOVERFLOWS       123  /* PQOF */
#define FTFROMPQOVERFLOWS     124
#define N_OLD_ATRS     (FTFLOWKIND + 1 + 4)  /* DSCP + OverflowPDUs */
#define LASTATTRIB      FTFROMPQOVERFLOWS    /* May be redefined below */
#endif


#define FTFORWARD              50
#define FTV1                   51
#define FTV2                   52
#define FTV3                   53
#define FTV4                   54
#define FTV5                   55

#define USER_ATTRIB(a)  (a >= FTV1 && a <= FTV5)
#define N_METER_ATRS    (FTV5+1 - FTFORWARD)
#define N_VBLS          (FTV5+1 - FTV1)  /* Nbr of user variables */

#if !NEW_ATR
#define N_DIST_ATRS             0
#else
#define FTDISTRIBUTIONS        65  /* Bit set for each distribution in flow */
#define FTTOPACKETSIZE         66
#define FTFROMPACKETSIZE       67
#define FTTOINTERARRIVALTIME   68
#define FTFROMINTERARRIVALTIME 69

#define FTTOBITRATE            72
#define FTFROMBITRATE          73
#define FTTOPDURATE            74
#define FTFROMPDURATE          75

#define FTTOTCPTIME            76
#define FTFROMTCPTIME          77
#define FTTOTCPSIZE            78
#define FTFROMTCPSIZE          79
#define FTTOTCPRATE1           80
#define FTFROMTCPRATE1         81
#define FTTOTCPRATE2           82
#define FTFROMTCPRATE2         83

#define FTTOTURNAROUNDTIME1    70
#define FTFROMTURNAROUNDTIME1  71

#define FTTOTURNAROUNDTIME2    84
#define FTFROMTURNAROUNDTIME2  85
#define FTTOTURNAROUNDTIME3    86
#define FTFROMTURNAROUNDTIME3  87
#define FTTOTURNAROUNDTIME4    88
#define FTFROMTURNAROUNDTIME4  89
#if 0
#define FTTOTRAINLENGTH        88
#define FTFROMTRAINLENGTH      89
#endif
#define FTTOFLOWOCTETS         90
#define FTFROMFLOWOCTETS       91
#define FTTOFLOWPDUS           92
#define FTFROMFLOWPDUS         93
#define FTFLOWTIME             94

#define LAST_DISTRIB           FTFLOWTIME

#define DISTRIB_ATTRIB(a)  (a >= FTTOPACKETSIZE && a <= LAST_DISTRIB)
#define N_DIST_ATRS   (LAST_DISTRIB+1 - FTDISTRIBUTIONS) 
# if LASTATTRIB < LAST_DISTRIB
#  undef LASTATTRIB
#  define LASTATTRIB      LAST_DISTRIB  /* max(basic, dist) */
# endif

#define TURNAROUND_ATTRIB(a)  ( \
            a == FTTOTURNAROUNDTIME || a == FTFROMTURNAROUNDTIME || \
            (a >= FTTOTURNAROUNDTIME2 && a <= FTFROMTURNAROUNDTIME5) )
#endif

#if NF_ASN_ATT || NF_OTHER_ATT
#define FTMETERID             112
#define FTLOWROUTEASN         113
#define FTLOWROUTEPREFIX      114
#define FTHIROUTEASN          115
#define FTHIROUTEPREFIX       116

#define NF_ATTRIB(a)  (a >= FTMETERID && a <= FTHIASWIDTH)
#define N_NF_ATRS         (FTHIASPREFIX+1 - FTMETERID)
#else
#define N_NF_ATRS               0
#endif

#if !NEW_ATR
# define N_TCP_ATRS              0
#else
# define FTTCPDATA             125
# define N_TCP_ATRS              1
#  if LASTATTRIB < FTTCPDATA
#   undef LASTATTRIB
#   define LASTATTRIB    FTTCPDATA  /* max(basic, dist, nf, tcp) */
#  endif
#endif  /* NEW_ATR */

#define N_ATTRIBS  (N_OLD_ATRS + N_METER_ATRS + N_DIST_ATRS \
                      + N_NF_ATRS + N_TCP_ATRS)

EXTFLOW Bit8 dist_atr[LASTATTRIB+1],  /* Distribution-valued */
  stream_atr[LASTATTRIB+1];  /* Needs to handle streams */

struct attrib_info {
   Bit8 attr,  /* Attribute number */
      distrib, stream;
   };
EXTFLOW struct attrib_info attribs[]
#if DECLARE
   = {
#if defined(NEW_ATR)
      FTTOPACKETSIZE,         1, 0,
      FTFROMPACKETSIZE,       1, 0,

      FTTOBITRATE,            1, 0,
      FTFROMBITRATE,          1, 0,
      FTTOPDURATE,            1, 0,
      FTFROMPDURATE,          1, 0,

      FTTOINTERARRIVALTIME,   1, 1,
      FTFROMINTERARRIVALTIME, 1, 1,

      FTTOTURNAROUNDTIME1,    1, 1,
      FTFROMTURNAROUNDTIME1,  1, 1,
      FTTOTURNAROUNDTIME2,    1, 1,
      FTFROMTURNAROUNDTIME2,  1, 1,
      FTTOTURNAROUNDTIME3,    1, 1,
      FTFROMTURNAROUNDTIME3,  1, 1,
      FTTOTURNAROUNDTIME4,    1, 1,
      FTFROMTURNAROUNDTIME4,  1, 1,

      FTTOTCPTIME,            1, 1,
      FTFROMTCPTIME,          1, 1,
      FTTOTCPSIZE,            1, 1,
      FTFROMTCPSIZE,          1, 1,
      FTTOTCPRATE1,           1, 1,
      FTFROMTCPRATE1,         1, 1,
      FTTOTCPRATE2,           1, 1,
      FTFROMTCPRATE2,         1, 1,

      FTTOFLOWOCTETS,         1, 1,
      FTFROMFLOWOCTETS,       1, 1,
      FTTOFLOWPDUS,           1, 1,
      FTFROMFLOWPDUS,         1, 1,
      FTFLOWTIME,             1, 1,

      FTTCPDATA,              0, 1,  /* Not a distrib, but uses streams */
# endif
      0,  0, 0  /* End marker */
   }
#endif
   ;

/* Global Variables */

EXTFLOW int  /* Performance statistics */
   n_hash_ents INIT(0),
   n_matches INIT(0),
   n_hash_compares INIT(0), n_hash_searches INIT(0);

EXTFLOW int kb_enabled;
EXTFLOW int display_enabled;


/* Signed comparisons of Bit32 a and Bit32 b */

#define scmp32(a,b) (a == b ? 0 : ((Bit32)(a-b) <= 0x80000000 ? +1 : -1))

#define scmp32_ge(a,b) ((Bit32)(a-b) <= 0x80000000)  /* True if a >= b */
#define scmp32_lt(a,b) ((Bit32)(a-b)  > 0x80000000)  /* True if a < b */


/* counter64 declared in snmplib\asn1.h */

#if SIZEOF_LONG_LONG == 8 || SIZEOF_LONG == 8


#define add_Bit32_to_counter64(c,u)  {  \
   c += (Bit32)(u);  \
   }
#define incr_counter64(c)  {  \
   ++c;  \
   }
#define subtr64(r64, c64,x64) {  \
   r64 = c64 - x64;  \
   }
#define assign64(x64,y64)  {  \
   x64 = y64;  \
   }

#define c64geint(x64,i)  (x64 >= i)
#define doublefrom64(x64)  (double)(x64)
#define setzero64(x64)  x64 = 0


#elif SIZEOF_LONG == 4


#define add_Bit32_to_counter64(c,u)  {  \
   c64arg = c.low;  if ((c.low += (Bit32)(u)) < c64arg) ++c.high;  \
   }
#define incr_counter64(c)  {  \
   c64arg = c.low;  if (++c.low < c64arg) ++c.high;  \
   }
#define subtr64(r64, c64,x64) {  \
   if ((r64.low = c64.low - x64.low) > c64.low) \
      r64.high = c64.high -1 - x64.high;  \
   else r64.high = c64.high - x64.high;  \
   }
#define assign64(x64,y64)  {  \
   x64.high = y64.high;  x64.low = y64.low;  \
   }

#define c64geint(x64,i) (x64.high != 0 ? 1 : (x64.low >= i))

#define doublefrom64(x64) (double)(x64.low)
   /* CAUTION: this assumes x64 fits in 32 bits */
#define setzero64(x64)  x64.high = x64.low = 0


#else
#error  sizeof(long) not 4 or 8 <<<<<<<<
#endif


EXTFLOW unsigned long c64arg;  /* Work variable for defines above */

#define TV_TRUE           1  /* TruthValues (SNMP, from RFC 1903) */
#define TV_FALSE          2

#define RS_ACTIVE         1  /* RowStatus (ditto) */
#define RS_NOTINSERVICE   2
#define RS_NOTREADY       3
#define RS_CREATEANDGO    4
#define RS_CREATEANDWAIT  5
#define RS_DESTROY        6

#define RS_UNUSED         0  /* Row not yet created by a manager */
#define RS_SET_CREATE     9  /* Set by RESERVE2 while creating a row */ 
/* MIB variables */

EXTFLOW int InactivityTimeout INIT(600L);  /* 10 minutes */
EXTFLOW int HighWaterMark INIT(65);  /* 65 % */
EXTFLOW int FloodMark INIT(95);  /* 95 % */
EXTFLOW int FloodMode INIT(TV_FALSE);

struct rdr_rec {
   int ci_Timeout;
   char ci_Owner[NAMESZ+1];
   Bit32 ci_LastTime;
   Bit32 ci_PrevTime;
   int ci_Status;
   int ci_RuleSet;
   Bit32 ci_MinPDUs, ci_TimeMark;  /* For nifty */
   int ci_old_status;
   struct rdr_rec *ci_rs_next;  /* rs_rdr chains */
   };

EXTFLOW struct rdr_rec ci[MXCLCTRS];
EXTFLOW struct rdr_rec *rs_rdr[MXRTBLS];  /* Ruleset -> cip (for nifty) */

EXTFLOW unsigned long pcap_LostPackets INIT(0);
EXTFLOW unsigned long noflowpackets INIT(0);

struct mgr_rec {  /* v4 */
   int mi_CurrentRuleSet;
   int mi_StandbyRuleSet;
   int mi_HighWaterMark;
   char mi_Owner[NAMESZ+1];
   Bit32 mi_TimeStamp;
   int mi_Status;
   int mi_RunningStandby;
   int mi_old_status;
   };
EXTFLOW struct mgr_rec mi[MXMANAGERS];

/* Meter outer block functions */

void startup_screen(void);
void show_meter_time(void);
void one_second_process(void);
void bump_noflowpkts(int if_nbr);
unsigned long iface_info(int if_nbr, int which);

/* Flowhash functions */

void pkt_extract(struct pkt *bp,
   const int type, const Bit8 *hdrp, const int hl);
void other_extract(struct pkt *bp,
   const Bit16 ethertype, const Bit16 lsap);
int handle_pkt(struct pkt *pp,
   const Bit16 ether_type, const Bit16 lsap, const Bit8 *ethp, 
   const Bit8 *p, const int pl);

void free_flow(struct flow *q);

#if NEW_ATR
struct distribution *get_dist(void);
void free_dist(struct distribution *d);
struct event *get_event(void);
void free_event(struct event *e);
void check_rates(Bit32 now);
void unlink_distrib_from_event(struct distribution *d);

struct pktdata *get_pktdata(void);
void free_pktdata(struct pktdata *pd);
struct stream *get_stream(void);
void free_stream(struct stream *sf);
struct stream_data *get_st_data(void);
void free_st_data(struct stream_data *sdp);

void terminate_all_streams(struct flow *fp,
   struct stream_data *sdp);
void terminate_stream(struct stream_data *sdp, struct stream *sp);

void tcp_stream_stats(struct flow *fp,
   struct stream_data *sdp, struct stream *sp);
void check_tcp_idle_streams(struct flow *fp, int gc_call);
int tcp_stream_update(struct flow *fp,
   struct stream *sp, const struct pktdata *pd);

int tcp_turnaround(int *pp_type, double *delta_us,
   struct flow *fp, struct stream *sp, struct pktdata *tp);

void flow_stream_stats(struct flow *fp,
   struct stream_data *std, struct stream *sp);
void check_other_idle_streams(struct flow huge *fp);
void other_stream_update(struct flow *fp,
   struct stream *sp, struct pktdata *tp);

struct stream *find_stream(struct flow *fp,
   int *flow_order, struct pkt *bp, double at_us);
#endif

int optimise_rule_table(int rs);
void empty_hash_chain(int rs);
void open_rule_set(int n, int open_rs);
Bit32 number_flow(void);
int garbage_collect(int incremental);
void more_garbage(void);
Bit32 active_flows(void);
struct flow *find_flow(Bit32 x);
void pkt_monitor(struct pkt *bp);
void show_stats(void);
void show_time(void);
void init_monitor(int n_interfaces);
void show_help(void);
void handle_kb(int ch);
void unpack_at_node(Bit8 *ap, const Bit8 *at_net, const Bit8 at_node);
void unpack_dn_node(Bit8 *ap, const Bit8 *dn_addr);
void save_time(void);
void zero_stats(int show_msg);

void open_log(void);  /* Debug functions */
void quack(int x);

/* Functions in met_vars.c */

void log_msg(int priority, int die, char *fmt, ...);
int alloc_rulespace(int rs, int rules, Bit16 size);
int free_rulespace(int rs);

