%
% x-kernel v3.3
%
% Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
%

\section{Uniform Protocol Interface (UPI)}\label{upi}

Each {\xk} protocol is encapsulated in a uniform protocol interface
(UPI).  The suite of protocols configured into the system form a {\em
protocol graph} and the collection of currently opened sessions
(connections) form a {\em session graph}.

\subsection{Type Definitions}\label{upi_type_defs}

\subsubsection{Protocol and Session Objects}\label{Protl_Sessn}
\index{Protocol Objects}
\index{Session Objects}

The {\var Protl} and {\var Sessn} structures are the fundamental
objects in the system.  Most fields in the {\var Protl} and {\var
Sessn} structures are not directly read or written by the programmer;
those that are available to the programmer are so indicated in the
comments.

\var
\begin{tabbing}
xxxx \= xxxx \= xxxxxxxxxxxxx \= xxxxxx \= xxxxx \= xxxxxxxx \= \kill
\>typedef struct protl \{\\
\>\>char         \>*name;      \>\>/* the protocol name, e.g., ``ethdrv'' */\\
\>\>char         \>*instName;  \>\>/* the instance name, e.g., ``SE0'' */\\
\>\>char         \>*fullName;  \>\>/* the name given in graph.comp, e.g., ``ethdrv/SE0'' */\\
\>\>char         \>*state;     \>\>/* readable/writable */\\
\>\>Binding      \>binding;    \>\>/* readable/writable */\\
\>\>int          \>id;\\
\>\>int          \>*traceVar;  \>\>/* readable */\\
\\
\>\>/* pointers to protocols configured below this one */\\
\>\>int          \>numdown;    \>\>/* readable - total number in down list */\\
\>\>int          \>downlistsz; \>\>/* size of downlist */\\
\>\>struct protl \>*down[8];   \>\>/* first 8 in down list */\\
\>\>struct protl \>**downlist; \>\>/* overflow from down array */\\
\\
\>\>/* interface functions */\\
\>\>XOpenFunc           \>\>open;\\
\>\>XOpenEnableFunc     \>\>openenable;\\
\>\>XOpenDisableFunc    \>\>opendisable;\\
\>\>XOpenDisableAllFunc \>\>opendisableall;\\
\>\>XOpenDoneFunc       \>\>opendone;\\
\>\>XCloseDoneFunc      \>\>closedone;\\
\>\>XDemuxFunc          \>\>demux;\\
\>\>XCallDemuxFunc      \>\>calldemux;\\
\>\>XControlProtlFunc   \>\>controlprotl;\\
\>\} *Protl;
\end{tabbing}

\begin{tabbing}
xxxx \= xxxx \= xxxxxxxxxxxxx \= xxxxxx \= xxxxx \= xxxxxxxx \= \kill
\>typedef struct sessn \{\\
\>\>char          \>*state;     \>\>/* readable/writable */\\
\>\>Binding       \>binding;    \>\>/* readable/writable */\\
\>\>int           \>rcnt;\\
\>\>unsigned char \>idle;\\
\\
\>\>/* pointers to open sessions below this one */\\
\>\>int           \>numdown;    \>\>/* readable - total number in down list */\\
\>\>int           \>downlistsz; \>\>/* size of downlist */\\
\>\>struct sessn  \>*down[8];   \>\>/* first 8 in down list */\\
\>\>struct sessn  \>**downlist; \>\>/* overflow from down array */\\
\\
\>\>/* interface functions */\\
\>\>XCloseFunc           \>\>close;\\
\>\>XPopFunc             \>\>pop;\\
\>\>XCallPopFunc         \>\>callpop;\\
\>\>XPushFunc            \>\>push;\\
\>\>XCallFunc            \>\>call;\\
\>\>XControlSessnFunc    \>\>controlsessn;\\
\>\>XGetParticipantsFunc \>\>getparticipants;\\
\>\>XDuplicateFunc       \>\>duplicate;\\
\\
\>\>/* pointers to protocols associated with this session */\\
\>\>struct protl  \>*myprotl;   \>\>/* session is an instance of this protocol */\\
\>\>struct protl  \>*up;        \>\>/* session was created by this protocol */\\
\>\>struct protl  \>*hlpType;   \>\>/* session was created on behalf of this protocol */\\
\>\} *Sessn;
\end{tabbing}
\rm

If you think of the {\xk} as implementing protocol and session graphs,
then each {\var Protl} represents a node in the protocol graph and
each {\var Sessn} represents a node in the session graph.  A
protocol's {\var down} vector represents protocol graph edges; it
contains pointers to the {\var Protl}s that are below the protocol in
the graph.  The same is true for a session's {\var down} vector.  The
fields {\var myprotl} and {\var up} in the {\var Sessn} structure link
a session to the protocols that own and created it, respectively.

For historical reasons, there are some fields in the actual {\var Protl}
and {\var Sessn} structures that aren't shown in this document.
These fields should not be used, as they will eventually be removed.

\subsubsection{Enable Objects}\label{enable_objs}
\index{enable objects}

Protocol writers use {\var Enable} objects to remember {\var
xOpenEnable} calls. Typically, a protocol saves a pointer to an {\var
Enable} object in its passive map, using {\var mapBind}. An {\var
Enable} object has a field for reference counting.  Calls to {\var
xOpenEnable} with identical participants (the calls are redundant with
respect to session creation) must be reference counted in order to
properly handle {\var xOpenDisable} calls.

\var
\begin{tabbing}
xxxx \= xxxx \= xxxxxxx \= xxxxxxxxxx \= \kill
\>typedef struct xenable \{\\
\>\>Protl   \>hlp;     \>/* upper protocol */\\
\>\>Protl   \>hlpType; \>/* upper protocol */\\
\>\>Binding \>binding; \>/* from mapBind */\\
\>\>int     \>rcnt;    \>/* use count */\\
\>\}Enable;
\end{tabbing}
\rm

\subsubsection{Return Values}\label{return_values}

Most routines have a return value type of {\var XkReturn}, which is
either {\var XK\_SUCCESS} or {\var XK\_FAILURE}.  Routines that return
type {\var Protl} or {\var Sessn} have a failure value of {\var
ERR\_PROTL} or {\var ERR\_SESSN}, respectively.  Some message handling
routines use type {\var XkHandle} (see Section~\ref{xPush}).  Severe
error conditions will result in console error messages and the
termination of the {\xk}.

\subsubsection{Function Types}\label{function_types}

The following function typedefs are used in the {\var Protl} and {\var
Sessn} structures.

\var
\begin{tabbing}
xxxx \= xxxxxxxxxxxxxxxxxx \= \kill
\>typedef struct sessn \>*(*XOpenFunc)(Protl, Protl, Protl, Part *);\\
\>typedef XkReturn     \>(*XOpenEnableFunc)(Protl, Protl, Protl, Part *);\\
\>typedef XkReturn     \>(*XOpenDisableFunc)(Protl, Protl, Protl, Part *);\\
\>typedef XkReturn     \>(*XOpenDisableAllFunc)(Protl, Protl);\\
\>typedef XkReturn     \>(*XOpenDoneFunc)(Protl, Protl, Sessn, Protl);\\
\>typedef XkReturn     \>(*XCloseDoneFunc)(Sessn);\\
\>typedef XkReturn     \>(*XDemuxFunc)(Protl, Sessn, Msg *);\\
\>typedef XkReturn     \>(*XCallDemuxFunc)(Protl, Sessn, Msg *, Msg *);\\
\>typedef int          \>(*XControlProtlFunc)(Protl, int, char *, int);\\
\>typedef XkReturn     \>(*XCloseFunc)(Sessn);\\
\>typedef XkReturn     \>(*XPopFunc)(Sessn, Sessn, Msg *, void *);\\
\>typedef XkReturn     \>(*XCallPopFunc)(Sessn, Sessn, Msg *, void *, Msg *);\\
\>typedef XkHandle     \>(*XPushFunc)(Sessn, Msg *);\\
\>typedef XkReturn     \>(*XCallFunc)(Sessn, Msg *, Msg *);\\
\>typedef int          \>(*XControlSessnFunc)(Sessn, int, char *, int);\\
\>typedef Part         \>*(*XGetParticipantsFunc)(Sessn);\\
\>typedef XkReturn     \>(*XDuplicateFunc)(Sessn);\\
\end{tabbing}
\rm

\subsection{Protocol and Session Operations}\label{protl-protl_ops}

This section defines the operations that protocols and sessions invoke
on each other.  In general, each of these operations invokes a
corresponding operation in the target protocol or session.  For
example, an {\var xOpen} call will result in the invocation of a
protocol-specific open routine, e.g., {\var udp\_open}.  For each
operation, we give the interface to both the generic {\xk} operation
and an example protocol-specific procedure that implements the generic
operation.  Although nearly the same, the specification for the
generic operation and the specification for the protocol-specific
routine typically differ in that a {\var self} pointer is passed to
the protocol-specific routine.

\subsubsection{xOpen}\label{xOpen}
\index{xOpen}

\noindent
The {\var xOpen} function is used by high-level protocol {\var hlp} to
actively open a session associated with low-level protocol {\var llp}
on behalf of high-level protocol {\var hlpType}.  Typically, {\var
hlp} and {\var hlpType} refer to the same protocol (see
Section~\ref{hlpdesc}).  The {\var participants} argument is a list of
addresses for each participant in the communication.  For this, and
all calls returning type {\var Protl} or {\var Sessn}, a return value
of {\var ERR\_PROTL} or {\var ERR\_SESSN}, respectively, indicates
failure. This must be checked by all callers before using the return
value.

Note that the high-level protocol will use its {\var self} object as
the first (and usually second) argument in {\var xOpen}, and the
lower-level protocol object as the third argument.  The lower-level
protocol's open routine will see its own {\var self} object as the
first argument, and the high-level protocols as the second and third
arguments.  This reversal of argument order preserves the convention
that the current protocol's self object is the first argument of the
protocol-specific function.
\medskip

{\it Generic}:
{\var Sessn xOpen(Protl hlp, Protl hlpType, Protl llp, Part *participants)}
\medskip

{\it Specific}:
{\var Sessn udp\_open(Protl self, Protl hlp, Protl hlpType, Part *participants)}

\subsubsection{xOpenEnable}\label{xOpenEnable}
\index{xOpenEnable}

\noindent
Used by high-level protocol {\var hlp} to passively open a session
associated with low-level protocol {\var llp} on behalf of high-level
protocol {\var hlpType}.  As with {\var xOpen}, {\var hlp} and {\var
hlpType} usually refer to the same protocol.  A passive open indicates
a willingness to accept connections initiated by remote participants.
A session is not actually returned, but the low-level protocol, by
convention, ``remembers'' this enabling, and later calls the
high-level protocol's {\var xOpenDone} operation to complete the
passive open.  The {\var participants} argument is an ordered list of
addresses of each participant for which the communication has been
enabled.  In most cases, it contains only a single element: the
address of the local participant.  A return value of 
{\var XK\_FAILURE} indicates failure.

The lower-level protocol generally ``remembers'' an invocation of its
{\var xOpenEnable} operation by binding an {\var Enable} object to the
participant information using {\var mapBind}.
\medskip

{\it Generic}:
{\var XkReturn xOpenEnable(Protl hlp, Protl hlpType, Protl llp,
Part *participants)}
\medskip

{\it Specific}:
{\var XkReturn udp\_openenable(Protl self, Protl hlp, Protl hlpType,
Part *participants)}

\subsubsection{xOpenDisable}\label{xOpenDisable}
\index{xOpenDisable}

\noindent
Used by high-level protocol {\var hlp} to undo the effects of an
earlier invocation of {\var xOpenEnable}.  The {\var hlp} and {\var
hlpType} arguments and the contents of the {\var participants}
argument must be the same as the ones given to {\var xOpenEnable}.
\medskip

{\it Generic}: 
{\var XkReturn xOpenDisable(Protl hlp, Protl hlpType, Protl llp,
Part *participants)}
\medskip

{\it Specific}: 
{\var XkReturn udp\_opendisable(Protl self, Protl hlp, Protl hlpType,
Part *participants)}

\subsubsection{xOpenDisableAll}\label{xOpenDisableAll}
\index{xOpenDisableAll}

\noindent
Used by high-level protocol {\var hlp} to inform low-level protocol
{\var llp} that all previous openEnables made by {\var hlp} should be
removed.
\medskip

{\it Generic}: 
{\var XkReturn xOpenDisableAll(Protl hlp, Protl llp)}
\medskip

{\it Specific}:
{\var XkReturn udp\_opendisableall(Protl self, Protl hlp)}

\subsubsection{xOpenDone}\label{xOpenDone}
\index{xOpenDone}

\noindent
Used by low-level protocol to inform a high-level protocol 
({\var hlp}) that a session ({\var session}) has now been created
corresponding to an earlier {\var xOpenEnable} on behalf of 
{\var hlpType}.

Note that the {\var hlpType} argument is not required in the generic
call because that value was saved in the {\var Sessn} object at the
time of the {\var xOpenEnable} call.
\medskip

{\it Generic}: 
{\var XkReturn xOpenDone(Protl hlp, Protl llp, Sessn session)}
\medskip

{\it Specific}:
{\var XkReturn udp\_opendone(Protl self, Protl llp, Sessn session,
Protl hlpType)}

\subsubsection{xCloseDone}\label{xCloseDone}
\index{xCloseDone}

\noindent
Used by a low-level protocol to inform the high-level protocol that
the session it originally opened has been closed by a peer participant.
\medskip

{\it Generic}: 
{\var XkReturn xCloseDone(Sessn session)}
\medskip

{\it Specific}:
{\var XkReturn udp\_closedone(Sessn self)}

\subsubsection{xDemux}\label{xDemux}
\index{xDemux}

\noindent
Used by low-level session {\var lls} to pass message {\var message} to
the high-level protocol that created it.  The high-level protocol demux
routine should find the appropriate session, creating it if necessary,
and {\var xPop} the message to the session.  See
Section~\ref{xCreateSessn} for guidelines on when session creation is
appropriate.
\medskip

{\it Generic}:
{\var XkReturn xDemux(Protl hlp, Sessn lls, Msg *message)}
\medskip

{\it Specific}:
{\var XkReturn udp\_demux(Protl self, Sessn lls, Msg *message)}

\subsubsection{xCallDemux}\label{xCallDemux}
\index{xCallDemux}

This call is like {\var xDemux} but provides an argument to contain a
return message.  Used with synchronous (RPC-like) protocols.
\medskip

{\it Generic}: 
{\var XkReturn xCallDemux(Protl hlp, Sessn lls, Msg *request, Msg *reply)}
\medskip

{\it Specific}:
{\var XkReturn udp\_calldemux(Protl self, Sessn lls, Msg *request, Msg *reply)}

\subsubsection{xControlProtl}\label{xControlProtl}
\index{xControlProtl}

Used by one protocol to act upon another protcol ({\var llp}) for
retrieving information or for setting processing parameters.  The
operation code {\var opcode} identifies the action; {\var buffer} is a
character buffer from which an argument is retrieved and/or into which
a result is placed; and {\var length} is the length of the buffer.
Returns an integer that indicates the length in bytes of the
information which was written into the buffer, or -1 to indicate an
error.  There are two ``classes'' of operations: standard ones that
may be implemented by more than one protocol, and protocol-specific
ones.  A full discussion of control operation codes is in
Section~\ref{control_ops}.
\medskip

{\it Generic}: 
{\var int xControlProtl(Protl llp, int opcode, char *buffer, int length)}
\medskip

{\it Specific}: 
{\var int udp\_controlprotl(Protl self, int opcode, char *buffer, intlength)}

\subsubsection{xClose}\label{xClose}
\index{xClose}

\noindent
Decrements the reference count of a {\var Sessn}, calling the
session's close function {\it only} if the reference count is zero.
\medskip

{\it Generic}: 
{\var XkReturn xClose(Sessn session)}
\medskip

{\it Specific}: 
{\var XkReturn udp\_close(Sessn self)}

\subsubsection{xPop}\label{xPop}
\index{xPop}

\noindent
Used by a protocol to pass an incoming message up to
session {\var hls} for processing, and to indicate the lower-level
session from which the message was received ({\var lls}).  This calls
the pop routine of the session {\var hls} and increments the session
reference count.  This call is invoked by a protocol on one of its own
sessions.

The {\var hdr} argument is passed directly to the protocol-specific
routine.  It is typically used to pass the header (which the demux
routine used to find the session) to the session's pop routine.
\medskip

{\it Generic}: 
{\var XkReturn xPop(Sessn hls, Sessn lls, Msg *message, void *hdr)}
\medskip

{\it Specific}:
{\var XkReturn udp\_pop(Sessn self, Sessn lls, Msg *message, void *hdr)}

\subsubsection{xCallPop}\label{xCallPop}
\index{xCallPop}

When a synchronous (RPC-like) protocol is demuxing a message to an
asynchronous protocol, {\var xCallPop} can be used to allow the upper
protocol to return a message.  This reply message may be the same one
passed to the synchronous protocol via {\var xCallDemux}.
\medskip

{\it Generic}: 
{\var XkReturn xCallPop(Sessn hls, Sessn lls, Msg *request, void *hdr,
Msg *reply)}
\medskip

{\it Specific}: 
{\var XkReturn udp\_callpop(Sessn self, Sessn lls, Msg *request, void *hdr,
Msg *reply)}

\subsubsection{xPush}\label{xPush}
\index{xPush}

\noindent
Used by a high-level protocol that opened session {\var lls} to pass
a message down through that session.  The return
value is an opaque handle on the message that was sent.  This handle
may be used to identify this message in subsequent 
{\var xControlProtl} and {\var xControlSessn} operations.  The message
handle may also take one of three special values: a return value of
{\var XMSG\_NULL\_HANDLE} indicates a successful push to a protocol
which does not generate handles, {\var XMSG\_ERR\_HANDLE} indicates
general failure, and {\var XMSG\_ERR\_WOULDBLOCK} indicates that a
session in non-blocking mode would normally have blocked the push.
\medskip

{\it Generic}: 
{\var XkHandle xPush(Sessn lls, Msg *message)}
\medskip

{\it Specific}:
{\var XkHandle udp\_push(Sessn self, Msg *message)}

\subsubsection{xCall}\label{xCall}
\index{xCall}

\noindent
Similar to {\var xPush} except that a reply message may be returned
through the argument {\var reply}.  Used with synchronous (RPC-like)
protocols.  Because the lower protocol typically retains no state for
the request message after {\var xCall} returns, a message handle is
not returned.  The message structure for the reply must be initialized
(see Section~\ref{msgConstructEmpty}).
\medskip

{\it Generic}: 
{\var XkReturn xCall(Sessn lls, Msg *request, Msg *reply)}
\medskip

{\it Specific}: 
{\var XkReturn udp\_call(Sessn self, Msg *request, Msg *reply)}

\subsubsection{xControlSessn}\label{xControlSessn}
\index{xControlSessn}

Used by one session to act upon another session ({\var lls}) for
retrieving information or for setting processing parameters.  The
operation code {\var opcode} identifies the action; {\var buffer} is a
character buffer from which an argument is retrieved and/or into which
a result is placed; and {\var length} is the length of the buffer.
Returns an integer that indicates the length in bytes of the
information which was written into the buffer, or -1 to indicate an
error.  There are two ``classes'' of operations: standard ones that
may be implemented by sessions of more than one protocol, and
protocol-specific ones.  A full discussion of control operation codes
is in Section~\ref{control_ops}.
\medskip

{\it Generic}: 
{\var int xControlSessn(Sessn lls, int opcode, char *buffer, int length)}
\medskip

{\it Specific}: 
{\var int udp\_controlsessn(Sessn self, int opcode, char *buffer, int length)}

\subsubsection{xGetParticipants}\label{xGetParticipants}
\index{xGetParticipants}

Used by one session to retrieve the participant list of another session,
{\var lls}.
\medskip

{\it Generic}:
{\var Part *xGetParticipants(Sessn lls)}
\medskip

{\it Specific}:
{\var Part *udp\_getparticipants(Sessn self)}

\subsubsection{xDuplicate}\label{xDuplicate}
\index{xDuplicate}

Increments the reference count of {\var session}.  This can be used to
create a permanent handle on {\var session} from a temporary handle,
or to create a new equivalent handle from an existing handle.  For a
full discussion of session reference counts, see the {\xk} Tutorial
\cite{Tutorial}.
\medskip

{\it Generic}:
{\var XkReturn xDuplicate(Sessn session)}
\medskip

{\it Specific}: 
{\var XkReturn udp\_duplicate(Sessn self)}

\subsection{Graph Manipulation Operations}\label{graph_manip_ops}

Unlike the previous set of operations, which protocols and sessions
invoke on each other to open/close connections and to send/receive
messages, the operations defined in this section actually manipulate
the protocol and session graphs; i.e., create nodes and edges.  These
operations are either called by the {\xk} at start-up time to create
and link together protocol objects, or by protocols at runtime to create
and link together session objects.

\subsubsection{xCreateProtl}\label{xCreateProtl}
\index{xCreateProtl}

Called during system start-up for each protocol in the graph.  The
function {\var func} is called to initialize a protocol object.  This
function must have a well-known name derived from the concatenation of
the protocol name and the string ``{\var \_init}'' (e.g., 
{\var udp\_init}).  This initialization function generally allocates and
initializes the protocol state and fills in the interface function
pointers.  Because function pointers are initialized to null functions
before {\var func} is called, only those functions actually used by
the protocol need be defined.

The use of {\var xCreateProtl} outside of initialization---for
example, to dynamically load new protocols---is not supported at this
time.

\var
\begin{tabbing}
\indent
Protl xCreateProtl(\=ProtlInitFunc func, char *name, char *instName, int *traceVar,\\
\>int downc, Protl *downv)
\end{tabbing}
\rm

{\var typedef void (*ProtlInitFunc)(Protl self)}

\subsubsection{xCreateSessn}\label{xCreateSessn}
\index{xCreateSessn}

Called by protocol {\var llp} to create a session that will handle
data associated with a common source/destination pair.  Usually called
in response to an {\var xOpen} call, or because data has arrived with
participants that match a previous {\var xOpenEnable} call.  By
convention, a protocol will only create one session at a time for a
source/destination pair, even if there have been multiple 
{\var xOpenEnable}'s that would match incoming data.

The session is initialized using information found in protocols 
{\var hlp}, {\var hlpType} and {\var llp}.  The new session's up pointer 
is set to {\var hlp} (this is where upward-bound messages through this
session will be delivered).  The count {\var downc} indicates how many
lower level sessions this session will use.  An array of lower
sessions themselves is passed as {\var downv}.  Sessions which use no
lower sessions may pass zero for {\var downc} and NULL for 
{\var downv}. The initialization function pointer {\var func} may be null;
otherwise this function should fill in the interface function pointers
in the {\var Sessn} structure.  These pointers are initialized to
default (usually null) functions by the system initialization code.
\medskip

\var
\begin{tabbing}
\indent
Sessn xCreateSessn(\=SessnInitFunc func, Protl hlp, Protl hlpType, Protl llp,\\
\>int downc, Sessn *downv)
\end{tabbing}
\rm

{\var typedef void (*SessnInitFunc)(Sessn self)}

\subsubsection{xDestroySessn}\label{xDestroySessn}
\index{xDestroySessn}

Destroys session objects.  It is the inverse of {\var xCreateSessn}.
Storage for {\var session} is freed, and if the state pointer of 
{\var session} is non-null, it is also freed.
\medskip

{\var XkReturn xDestroySessn(Sessn session)}
\medskip

\subsubsection{xGetProtlByName}\label{xGetProtlByName}
\index{xGetProtlByName}

Returns a capability for (pointer to) a protocol object given its
mnemonic name.  See the discussion of {\var graph.comp} in
Section~\ref{config}.
\medskip

{\var Protl xGetProtlByName(char *name)}

\subsubsection{xSetSessnDown}\label{xSetSessnDown}
\index{xSetSessnDown}

Sets the {\var index}th member of {\var self}'s down vector to be
{\var session}.  It increments the {\var Sessn} field {\var numdown}
as a side effect.
\medskip

{\var XkReturn xSetSessnDown(Sessn self, int index, Sessn session)}

\subsubsection{xGetProtlDown}\label{xGetProtlDown}
\index{xGetProtlDown}

Returns the {\var index}th member of {\var self}'s down vector.
Returns {\var ERR\_PROTL} if the index is larger than the down vector.
\medskip

{\var Protl xGetProtlDown(Protl self, int index)}

\subsubsection{xGetSessnDown}\label{xGetSessnDown}
\index{xGetSessnDown}

Returns the {\var index}th member of {\var self}'s down vector.
Returns {\var ERR\_SESSN} if the index is larger than the down vector.
\medskip

{\var Sessn xGetSessnDown(Sessn self, int index)}

\subsubsection{xMyProtl}\label{xMyProtl}
\index{xMyProtl}

Returns the {\var myprotl} pointer of {\var self}.
\medskip

{\var Protl xMyProtl(Sessn self)}

\subsubsection{xSetUp}\label{xSetUp}
\index{xSetUp}

Resets the up pointer of {\var session} to {\var hlp}.  The {\var up}
pointer of a session is initialized in {\var xCreateSessn}, so {\var
xSetUp} is only used for extraordinary manipulation of the session
graph.
\medskip

{\var void xSetUp(Sessn session, Protl hlp)}

\subsubsection{xGetUp}\label{xGetUp}
\index{xGetUp}

Returns the up pointer of {\var session}.
\medskip

{\var Protl xGetUp(Sessn session)}

\subsubsection{xHlpType}\label{xHlpType}
\index{xHlpType}

Returns the {\var hlpType} argument that was used to create 
{\var session}.
\medskip

{\var Protl xHlpType(Sessn session)}

\subsection{Utility Operations}\label{utility_ops}

\subsubsection{xIsProtl}\label{xIsProtl}
\index{xIsProtl}

Returns true if {\var object} is a protocol; returns false if 
{\var object} was either never initialized or has been badly clobbered.
\medskip

{\var bool xIsProtl(Protl object)}

\subsubsection{xIsSessn}\label{xIsSessn}
\index{xIsSessn}

Returns true if {\var object} is a session; returns false if 
{\var object} was either never initialized or has been badly clobbered.
\medskip

{\var bool xIsSessn(Sessn object)}

\subsubsection{xIsValidProtl}\label{xIsValidProtl}
\index{xIsValidProtl}

A protocol created with {\var xCreateProtl} is kept in a system map
and removed when the protocol is destroyed.  {\var xIsValidProtl}
can be used to determine whether a random {\var Protl} handle 
({\var protocol)} is in this map and can thus be used safely.
\medskip

{\var bool xIsValidProtl(Protl protocol)}

\subsubsection{xIsValidSessn}\label{xIsValidSessn}
\index{xIsValidSessn}

A session created with {\var xCreateSessn} is kept in a system
map and removed when the session is destroyed.  {\var xIsValidSessn}
can be used to determine whether a random {\var Sessn} handle 
({\var session}) is in this map and can thus be used safely.
\medskip

{\var bool xIsValidSessn(Sessn session)}

\subsubsection{xPrintProtl}\label{xPrintProtl}
\index{xPrintProtl}

Displays some information about the state of {\var protocol}.
\medskip

{\var void xPrintProtl(Protl protocol)}

\subsubsection{xPrintSessn}\label{xPrintSessn}
\index{xPrintSessn}

Displays some information about the state of {\var session}.
\medskip

{\var void xPrintSessn(Sessn session)}

\subsection{Usage Rules}\label{upi_usage}

This section has some protocol design rules that protocol writers
should follow in order to develop ``well-behaved'' protocols that
interact properly with other protocols with which they might be
composed.

\subsubsection{Initializing a Protocol}\label{protl_init}

At system boot time, the {\xk} calls {\var xCreateProtl} for each
protocol configured into the kernel (see Section~\ref{config}).  
{\var xCreateProtl}, in turn, calls the protocol's init routine (where 
for a protocol named `yap', this initialization routine must be named 
{\var yap\_init}).  The work generally done by this routine is illustrated
by an example protocol in the {\xk} Tutorial \cite{Tutorial}.

\subsubsection{hlp and hlpType}\label{hlpdesc}
\index{hlp}
\index{hlpType}

The operations {\var xOpen}, {\var xOpenEnable}, and 
{\var xOpenDisable} take two high-level protocols, {\var hlp} and 
{\var hlpType}.  {\var hlp} is the protocol to which the new lower session
should route incoming messages.  The lower protocol uses 
{\var hlpType} to determine which messages the new session should handle.
For example, when {\var eth\_open} is called with IP as the 
{\var hlpType}, ETH knows that the new session will deal with packets that
have the IP ethernet type.  The lower protocol typically determines
the number that corresponds to {\var hlpType} by using it in a call to
{\var relProtNum} (see Sections~\ref{relProtNum} and
\ref{protocol_tables}).  The lower protocol passes {\var hlp} and
{\var hlpType} down to {\var xCreateSessn}.

Most protocols use their {\var self} pointer as both {\var hlp} and
{\var hlpType} when making these calls. Virtual protocols (see below)
are the exception.

\subsubsection{Protocol Realms}\label{protocol_realms}

Although the {\xk} defines a single interface for all protocols, not
all protocols are created equal.  Protocols can be classified into
different categories, which we call realms.  Chances are, any protocol
you write falls into one of the following realms.  In some cases, the
realm into which a protocol falls defines both a restricted subset of
the interface that the protocol implements, and the set of protocols
with which it may be composed.

\paragraph{Asynchronous Protocols}{\ }

\smallskip
\noindent
Most protocols (e.g., protocols like IP, TCP, and UDP) fall in this
category.  The {\xk} supports asynchronous protocols through the use
of {\var xPush}, {\var xPop} and {\var xDemux} operations.
Asynchronous protocols are typically symmetric in the sense that the
protocols' sessions process both incoming and outgoing messages.
While it seems possible for asynchronous protocols to have asymmetric
sessions (a given session can handle only incoming or outgoing
messages, but not both), we have thus far been able to make all our
asynchronous protocols symmetric, and we strongly encourage such
designs.  Knowing that any low-level protocols you may use are
symmetric enhances your ability to compose protocols and makes
implementing a given protocol much easier.

\paragraph{Synchronous Protocols}{\ }

\smallskip
\noindent
These are RPC protocols.  They are typically asymmetric in the sense
that client-side sessions and the server-side sessions are quite
different.  The {\xk} explicitly supports synchronous/asymmetric
sessions through the use of {\var xCall}, {\var xCallPop} and 
{\var xCallDemux}.  Since synchronous protocols are asymmetric, 
{\var xCall} is used on the client side and {\var xCallPop} and 
{\var xCallDeumx} are used on the server side.

Note that some protocols lie on the boundary between the synchronous
and asynchronous realms.  For example, a protocol that implements RPC
(as opposed to one that uses it) probably looks asynchronous from the
bottom (i.e., lower level protocols call its {\var xPop} routine), but
synchronous from above (i.e., higher level protocols call its 
{\var xCall} routine).

\paragraph{Control Protocols}{\ }

\smallskip
\noindent
These protocols support neither a {\var xPush/xPop} nor a 
{\var xCall/xCallPop} interface.  Typically, only control operations 
may be performed on these protocols.  ARP and ICMP fall into this category.

\subsubsection{Anchor Protocols}\label{anchor_protls}

Anchor protocols sit either at the top or the bottom of a protocol
stack and provide an interface between the {\xk} and the system in
which the {\xk} is embedded.  Top-level anchor protocols look like an
{\xk} protocol from the bottom, but provide an Application Programmer
Interface to the {\xk}.  Bottom-level anchor protocols (e.g., device
drivers) look like a protocol from the top, but typically interface
with the lower levels of the surrounding system or with network
hardware.

Writing anchor protocols involves careful synchronization of external
threads with {\xk} threads and objects (see
Section~\ref{ext-threads}).

\subsubsection{Virtual Protocols}\label{virtual_protls}

Virtual protocols occupy places in the protocol (and sometimes the
session) graphs, but they neither produce nor interpret network
headers.  They typically make decisions about how messages should be
routed through the session graph based on participants in {\var xOpen}
or on properties of messages, such as size.

The {\var xOpen}, {\var xOpenEnable}, and {\var xOpenDisable} routines
of virtual protocols differ from those of conventional protocols.  A
virtual protocol's implementation of {\var xOpen}, for example, will
usually make an {\var xOpen} call to its lower protocols using the
{\var hlpType} that was passed into the virtual protocol, but using
its {\var self} pointer as {\var hlp}.  This allows arbitrary chains
of virtual protocols to insert their sessions between the upper and
lower conventional sessions while still passing ``type information''
from the upper protocol to the lower protocol.

Note that virtual protocols can be either synchronous (support the
{\var xCall}/{\var xCallPop}/{\var xCallDemux} interface) or
asynchronous (support the {\var xPush}/{\var xPop}/{\var xDemux}
interface).

\subsection{Default Operations}\label{default_ops}

Since many protocols' UPI operations look very similar, the {\xk}
provides some library operations that do much of the standard work of
some of the operations.  Many protocols can call these default
operations, or at the very least, these default routines can serve as
a template for writing the corresponding protocol-specific routine.

\subsubsection{defaultOpenEnable}\label{defaultOpenEnable}
\index{defaultOpenEnable}

Binds {\var key} to an {\var Enable} object with {\var hlp} and 
{\var hlpType}.  If a previous binding exists for the given key and
protocols, the reference count of that {\var Enable} object will be
increased.  {\var defaultOpenEnable} will fail if a previous binding
exists for this key that does not match the protocols.
\medskip

{\var XkReturn defaultOpenEnable(Map map, Protl hlp, Protl hlpType, void *key)}

\subsubsection{defaultOpenDisable}\label{defaultOpenDisable}
\index{defaultOpenDisable}

Undoes the effect of a previous {\var defaultOpenEnable}. Returns
failure if no appropriate {\var Enable} object exists (e.g., if
nothing exists for the given key or if the protocols don't match the
saved values in the {\var Enable} object).
\medskip

{\var XkReturn defaultOpenDisable(Map map, Protl hlp, Protl hlpType, void *key)}

\subsubsection{defaultOpenDisableAll}\label{defaultOpenDisableAll}
\index{defaultOpenDisableAll}

Removes all {\var Enable} objects bound in {\var map} with protocol
{\var hlp}.  If {\var func} is non-zero, it is called with the 
({\var key}, {\var Enable} *) pair for each {\var Enable} object in the map
before it is removed.
\medskip

{\var XkReturn defaultOpenDisableAll(Map map, Protl hlp, DisableAllFunc func)}
\medskip

{\var typedef void (*DisableAllFunc)(void *key, Enable *e)}

\subsubsection{defaultVirtualOpenEnable}\label{defaultVirtualOpenEnable}
\index{defaultVirtualOpenEnable}

Designed to be used by virtual protocols.  In addition to the binding
performed by {\var defaultOpenEnable}, an {\var xOpenEnable} is
performed on each lower protocol in the null-terminated array 
{\var llp} (using {\var participants)}, causing the lower protocols to
deliver packets for {\var hlpType} to the virtual protocol 
{\var self}.  If any of these {\var xOpenEnable}s fail, {\var
defaultVirtualOpenEnable} backs out of the entire operation.  Assumes
that the passive map is keyed on {\var hlpType}.
\medskip

\var
\begin{tabbing}
\indent
XkReturn defaultVirtualOpenEnable(\=Protl self, Map map, Protl hlp,
Protl hlpType, Protl *llp,\\
\>Part *participants)
\end{tabbing}
\rm

\subsubsection{defaultVirtualOpenDisable}\label{defaultVirtualOpenDisable}
\index{defaultVirtualOpenDisable}

Undoes the effect of a previous {\var defaultVirtualOpenEnable}.
\medskip

\var
\begin{tabbing}
\indent
XkReturn defaultVirtualOpenDisable(\=Protl self, Map map, Protl hlp,
Protl hlpType, Protl *llp,\\
\>Part *participants)
\end{tabbing}
\rm

\subsubsection{Usage}\label{upi_def_usage}

Figure~\ref{fig:default} illustrates an example of how a protocol might
simplify its {\var enable}/{\var disable} routines using these operations.

\begin{figure}
\caption{Using default routines \label{fig:default}}
\begin{verbatim}
static XkReturn
yapOpenEnable(Protl self, Protl hlp, Protl hlpType, Part *p)
{
    long   key;
    PState *ps = self->state;

    key = getRelProtNum(hlpType, self));
    return defaultOpenEnable(ps->passive_map, hlp, hlpType, &key);
}

static XkReturn
yapOpenDisable(Protl self, Protl hlp, Protl hlpType, Part *p)
{
    long   key;
    PState *ps = self->state;

    key = getRelProtNum(hlpType, self));
    return defaultOpenDisable(ps->passive_map, hlp, hlpType, &key);
}

static XkReturn
yapOpenDisableAll(Protl self, Protl hlp)
{
    PState *ps = self->state;

    return defaultOpenDisableAll(ps->passive_map, hlp, NULL);
}
\end{verbatim}
\end{figure}
