#ifdef KERNEL
#ifndef	NRPC
#include "../DOT/rpc.h"
#endif
#else KERNEL
#define NRPC 1                  /* KLUDGE! */
#endif KERNEL

#if	NRPC > 0

#ifndef	VALID_RPC
#define	VALID_RPC		/* Enable the RPC facilities */
#endif

/*
 * jam 841026-29-30-31
 * jht 850522 -- rpc, efs, dfs now autoconfigured pseudo-device subsystems.
 * sas 850907 -- moved signal defines and macros here from rpcsignal.h
 * sas 851002 -- Fix to completely broken hash scheme.
 */

/*
 * Errors which may be detected on the local
 * and/or remote machines.  These are the
 * ONLY errors which may be contained in an
 * ERROR packet and are the only ones that
 * will be passed to the client error
 * function.
 *
 * The errors have been moved to errno.h and
 * have entries in errlst.c.
 */

#define RPC_FIND		0	/* Search for something */
#define RPC_MAKE		1	/* Search; make if not found */

/*
 * Packet header.  Compatible with Valid 7.0
 * packet headers; lifetime changed to client
 * generation number, though.  version is always
 * 0 for 7.0 packets.
 */
typedef struct rpc_header
{
	node_t		source;		/* Node this packet was sent from */
	u_long		client;		/* The id of the client */
	u_long		seqno;		/* Sequence number from client */
	u_long		sourcegen;	/* Generation of the sender */
	u_long		clientgen;	/* Client generation */
	u_short		type;		/* Packet type */
	u_short		class;		/* Class of call */
	u_short		operation;	/* Specific operation */
	u_short		version;	/* Version number */
	u_short		resvd;
} rpc_header_t;

/*
 * The current version number is split
 * into two fields: major and minor.
 * If the major numbers match then the
 * two versions are compatible.
 */
#define RPC_VERSION		rpc_makeVersion(0, 1)
#define rpc_makeVersion(m,n)	(((m) << 8) | (n))
#define rpc_majorVersion(v)	(((v) >> 8) & 0xFF)
#define rpc_minorVersion(v)	((v) & 0xFF)
#define rpc_versionCompat(x,y)	(((x) & 0xFF00) == ((y) & 0xFF00))

typedef struct sockaddr_rpc
{
	short		addr_family;	/* Address family (AF_RPC) */
	node_t		node;		/* Destination node */
	u_long		client;		/* Client ID */
} rpc_sockaddr_t;

/*
 * Enumeration of possible RPC packet types:
 *
 *	CALL is a request that a remote
 * function be executed.  They will be retrans-
 * mitted until a CALLACK, RETURN, or ERROR
 * is received.  A RETURN or ERROR must be
 * received for the call to be considered
 * complete.
 *
 *	CALLACK is sent by the server to stop
 * the caller from retransmitting a CALL.  It
 * indicates that the server has successfully
 * received the CALL.
 *
 *	RETURN packets contain data from remote
 * function.  When duplicate RETURN packets are
 * received they evoke a RETURNACK.
 *
 *	ERROR packets indicate that the call
 * was not (completely) executed by the remote
 * function; otherwise ERROR packets have the
 * same effects as RETURN packets.  Note: the
 * ERROR packet is not used for remote function
 * errors; these must be encoded in RETURN
 * packets.
 *
 *	RETURNACK is sent by the caller to stop
 * the server from retransmitting a RETURN or
 * ERROR.  It indicates that the caller has
 * successfully received the RETURN or ERROR.
 *
 * The actual values of the packet types are
 * compatible with Valid 7.0 RPC.
 */
#define RPCPKT_CALL		1	/* Call */
#define RPCPKT_CALLACK		5	/* Call acknowledge */
#define RPCPKT_RETURN		2	/* Normal return */
#define RPCPKT_ERROR		4	/* Error return */
#define RPCPKT_RETURNACK	3	/* Return acknowledge */

typedef struct rpc_clientId
{
	node_t		node;		/* Node client resides on */
	long		generation;	/* Node generation client exists in */
	long		id;		/* Unique ID within node/generation */
} rpc_clientId_t;

typedef struct rpc_clientClass
{
	struct rpc_clientClass *forw;	/* Pointer to next class in list */
	struct rpc_clientClass *back;	/* Pointer to next class in list */
	char		*name;		/* Class name */
	int		class;		/* Class number */
	int		(*ret)();	/* Function to call with return pkt */
	int		(*error)();	/* Function to call with error */
	int		(*exception)();	/* Function to call on exception */
	int		failrate;	/* Maximum failure rate (exponent) */
	int		maxwait;	/* Maximum wait for a call */
} rpc_clientClass_t;

typedef struct rpc_entry
{
	char		*name;		/* Function name */
	int		ncalls;		/* Number of calls to this function */
	caddr_t		(*call)();	/* Function for this operation */
} rpc_entry_t;

typedef struct rpc_serverClass
{
	struct rpc_serverClass *forw;	/* Pointer to next class in list */
	struct rpc_serverClass *back;	/* Pointer to next class in list */
	char		*name;		/* Class name */
	int		class;		/* Class number */
	int		(*call)();	/* Function to call with call pkt */
	int		(*abort)();	/* Function to call to abort call */
	int		(*exception)();	/* Function to call on exception */
	int		failrate;	/* Maximum failure rate (exponent) */
	int		maxwait;	/* Maximum wait for a call */
	int		noperations;	/* Number of operations */
	rpc_entry_t	*optable;	/* Operations for this service */
} rpc_serverClass_t;

/*
 * Client state descriptors are allocated on
 * the client side for each new client using
 * RPC.  They are freed only at the request
 * of the client.
 */
typedef struct rpc_clientState
{
	struct rpc_clientState *forw;	/* Link in state list */
	struct rpc_clientState *back;	/* Link in state list */
	u_long		seqno;		/* Current sequence number */
	int		state;		/* Current state */
	u_long		clientId;	/* ID supplied by client */
	rpc_clientClass_t *classp;	/* Class for most recent call */
	connection_t	*conn;		/* Connection to server node */
	rpc_header_t	*pkt;		/* Current call or return packet */
	int		maxretries;	/* Maximum number of retries */
	int		retryhz;	/* Base number of hz for retry */
	int		retries;	/* Number of retries so far */
	long		time;		/* Time for retries, etc. */
} rpc_clientState_t;

/*
 * Enumeration of client states:
 *
 *	IDLE indicates that the client has
 * no outstanding call.  New descriptors are
 * created in this state.  When a call is
 * made IDLE transitions to CALLING.
 *
 *	CALLING indicates that the client
 * has made a call which is periodically
 * being retransmitted.  If a RETURN or
 * ERROR is received CALLING transitions
 * to IDLE.  If a CALLACK is received
 * CALLING transitions to WANTRETURN.
 * being retransmitted.  If a CALLACK
 * packet is received CALLING transitions
 * to WANTRETURN.  If a RETURN or ERROR
 * packet is received, or if the server
 * crashes CALLING transitions to IDLE.
 *
 *	WANTRETURN indicates that a
 * CALLACK packet has been received but
 * not a RETURN or ERROR packet.  Receipt
 * of either packet, or the server crashing
 * will cause WANTRETURN to transition to
 * IDLE.
 */
#define RPCSTATE_IDLE		1	/* Idle */
#define RPCSTATE_CALLING	2	/* Sending the call packet */
#define RPCSTATE_WANTRETURN	3	/* Waiting for a return packet */

/*
 * The server state descriptor exists on the
 * server.  It is slightly misnamed since it
 * really describes a client for whim the server
 * has done work.  Once allocated, server
 * descriptors are only freed after they have
 * been idle for a sufficient time.
 */
typedef struct rpc_serverState
{
	struct rpc_serverState *forw;	/* Link in state list */
	struct rpc_serverState *back;	/* Link in state list */
	int		state;		/* Current state */
	connection_t	*conn;		/* Connection to client node */
	u_long		clientgen;	/* Generation number of client */
	u_long		clientId;	/* ID from client */
	rpc_serverClass_t *classp;	/* Class for most recent call */
	u_long		seqno;		/* Current sequence number */
	u_short		operation;	/* Operation being performed */
	rpc_header_t	*pkt;		/* Current call or return packet */
	int		maxretries;	/* Maximum number of retries */
	int		retryhz;	/* Base number of hz for retry */
	int		retries;	/* Number of retries so far */
	long		time;		/* Time for retries, etc. */
	u_long		cookie;		/* Special -- hold seqno */
} rpc_serverState_t;

/*
 * Enumeration of server states:
 *
 *	IDLE indicates that the client has
 * no outstanding calls.  New descriptors
 * are created in this state.
 *
 *	WORKING indicates that a CALL packet
 * has been received from the client but the
 * server has not finished yet.  WORKING
 * transitions to RETURNED when the server
 * finishes, or ABORTED if the client crashes.
 *
 *	ABORTED indicates that the client
 * crashed but the server is still working on
 * the request.  ABORTED will transition to
 * IDLE when the server finishes.
 *
 *	RETURNED indicates that the server
 * has finished and a RETURN packet is being
 * retransmitted periodically.  When a RETURNACK
 * packet or another CALL packet is received
 * RETURNED transitions to the IDLE state.
 */
#define RPCSTATE_IDLE		1	/* Idle */
#define RPCSTATE_WORKING	10	/* Servicing a call request */
#define RPCSTATE_ABORTED	11	/* Servicing an aborted call */
#define RPCSTATE_RETURNED	12	/* Sending return packet */


/*
 * Hash table header 
 *
 * (hash) --> entry --> entry --> entry --> NULL
 *   |   forw      forw      forw   ^  forw
 *   |    <--       <--       <--   |
 *   |   back       back     back   |
 *   |				    |
 *   +------------------------------+
 *         tail
 */
typedef struct rpc_hash {
	caddr_t		forw;		/* forward pointer */
	caddr_t		tail;		/* tail pointer */
} rpc_hash_t;

/* BUG -- These macros must be called at priority */
/*
 * Add entry to end of hash bucket queue
 */
#define rpc_addToTable(hash, entry) \
		insque(entry, hash->tail);

/*
 * Delete entry from hash bucket queue, square up tail pointer
 */
#define rpc_removeFromTable(hash, entry) \
		remque(entry);	\
		entry->back = entry->forw = 0;

/* END HASH */

#define rpc_maxRetries(statep)	((statep)->maxretries)
/* BUG hz should not be declared here */
extern int hz;
#define rpc_retryTime(statep) \
	(((statep)->retryhz << MIN((statep)->retries, 5)) / hz)

/*
 * The server can free state descriptors
 * which have been idle over some interval.
 * This interval must be greater than the
 * maximum time a packet can exist in the
 * network, including ALL queues.
 *
 * This used to be 240 which is an outrageously long amount of
 * time for a local area net.  Since Valid's RPC will never run over internet,
 * long haul, or anything more than a single cable, 120 seconds should
 * be long enough to accommodate the retransmit timeout.
 */
#define RPC_SERVERCLEANTIME	120

/*
 * Each client class has a return function
 * and an error function that get called,
 * eventually, in response to an rpc_call()
 * call.
 */
#define rpc_classReturn(classp,clientId,results) \
	((classp)->ret == NULL ? 0 : (*(classp)->ret)(clientId,results))
#define rpc_classError(classp,clientId,err) \
	((classp)->error == NULL ? 0 : (*(classp)->error)(clientId,err))

/*
 * On the server, each unique call causes
 * the call function for the specified class
 * to be called.  At any time before the call
 * does an rpc_return() it may be aborted if
 * the abort function for that class is called.
 */
#define rpc_classCall(classp,clientConn,clientId,classp,op,params,cookie) \
	((classp)->call == NULL ? 0 : \
		(*(classp)->call)(clientConn,clientId,classp,op,params,cookie))
#define rpc_classAbort(classp,clientConn,clientId,cookie) \
	((classp)->abort == NULL ? 0 : (*(classp)->abort)(clientConn,clientId,cookie))

/*
 * Client and server classes will have their
 * exception functions called when a node comes
 * up or goes down.
 */
#define rpc_classException(classp,conn,exception) \
	((classp)->exception == NULL ? 0 : \
		(*(classp)->exception)(conn,exception))

/*
 * RPC_SPL must raise the processor to a priority higher
 * than rpc interrupts and higher than the rpc daemons.
 *
 * RPC_PRIO_CLIENT is the priority level at which a client process sleeps.
 * RPC_PRIO_SERVER is the priority level at which server processes sleep.
 */
#define RPC_SPL()	spl5()
#define RPC_PRIO_CLIENT (PZERO-1)       /* rpc callers are uninterruptible */
#define RPC_PRIO_SERVER (PZERO-8)       /* rpc servers are uninterruptible */

/*
 * ETERNITY is the most distant time in the
 * future.  currentTime is the current time
 * (in seconds) and the macro timeUntil returns
 * the number of seconds (possibly negative)
 * until a given time is reached.  The macro
 * UPTIME returns the number of seconds the
 * system has been up.
 */
#define ETERNITY	0x7FFFFFFF
#define currentTime	(time.tv_sec)
#define timeUntil(t)	((t) - currentTime)
#define UPTIME()	(currentTime - boottime.tv_sec)

/*
 * binarymod() can be used to take the remainder
 * when the first number is divided by the second
 * when the numbers are both non-negative and it
 * is suspected that the divisor is is a power of
 * two.
 */
#define binarymod(k,m)	((m) & ((m)-1) ? (k)%(m) : (k) & ((m)-1))

/*
 * Well known RPC classes.
 */
#define RPC_CLASS_EFS		1	/* Extended filesystem */
#define RPC_CLASS_DFS		2	/* Distributed filesystem */
#define RPC_CLASS_SIGNAL	6	/* Signal mechanism */

/*
 * definitions, macros for signal class
 */
#define RPCSIGNAL_PSIGNAL	0
#define RPCSIGNAL_CHANGE	1

#define SIGNALCLIENT	((u_long)0x01000000)
#define CHANGECLIENT	((u_long)0x02000000)
#define signalclient(p)	(SIGNALCLIENT | (u_long)(p))
#define changeclient(p)	(CHANGECLIENT | (u_long)(p))
#define clienttype(c)	((u_long)(c) & 0xFF000000)
#define clientproc(c)	((struct proc *)((c) & 0x00FFFFFF))

#else	NRPC > 0

#ifdef	VALID_RPC
#undef	VALID_RPC		/* Disable the RPC facilities */
#endif

#endif	NRPC > 0
