371 lines
14 KiB
C
371 lines
14 KiB
C
#ifndef PROTOCOL_H
|
|
#define PROTOCOL_H
|
|
/*
|
|
* Copyright 1990 Silicon Graphics, Inc. All rights reserved.
|
|
*
|
|
* Protocol interface.
|
|
*/
|
|
#include "datastream.h"
|
|
#include "expr.h"
|
|
#include "scope.h"
|
|
|
|
struct snooper;
|
|
struct snooppacket;
|
|
struct snoopfilter;
|
|
struct protostack;
|
|
|
|
typedef struct protocol {
|
|
/* mandatory statically initialized state */
|
|
char *pr_name; /* string name */
|
|
int pr_namlen; /* and length */
|
|
char *pr_title; /* verbose name */
|
|
int pr_id; /* fast identifier */
|
|
enum dsbyteorder pr_byteorder; /* byte order */
|
|
int pr_maxhdrlen; /* frame header size */
|
|
struct protofield *pr_discriminant; /* nested type field */
|
|
/* protocol operation pointers */
|
|
int (*prop_init)(); /* (re)initialize */
|
|
int (*prop_setopt)(); /* set option */
|
|
void (*prop_embed)(); /* embed in protocol */
|
|
Expr *(*prop_resolve)(); /* resolve string */
|
|
enum exprtype (*prop_compile)(); /* compile raw filter */
|
|
int (*prop_match)(); /* match nested proto */
|
|
int (*prop_fetch)(); /* fetch field */
|
|
void (*prop_decode)(); /* decode frame */
|
|
/* optional statically initialized state */
|
|
unsigned short pr_flags; /* optional flags */
|
|
unsigned short pr_numoptions; /* number of options */
|
|
struct protoptdesc *pr_optdesc; /* option descriptors */
|
|
int (*pr_xdrstate)(); /* xdr decode state */
|
|
/* automatically initialized state */
|
|
struct scope pr_scope; /* symbol table */
|
|
int pr_level; /* decoding level */
|
|
} Protocol;
|
|
|
|
/*
|
|
* Initialized declaration macro for a protocol interface object.
|
|
* Tag is the prefix of the interface structure and of its operations.
|
|
* Name must be a string constant or a sized char array.
|
|
*/
|
|
#define DefineProtocol(tag, name, title, id, order, maxhdrlen, discrim, \
|
|
flags, optdesc, numopts, xdrstate) \
|
|
int makeident2(tag,_init)(); \
|
|
int makeident2(tag,_setopt)(int, char *); \
|
|
void makeident2(tag,_embed)(Protocol *, long, long); \
|
|
Expr *makeident2(tag,_resolve)(char *, int, struct snooper *); \
|
|
ExprType makeident2(tag,_compile)(struct protofield *, Expr *, Expr *, \
|
|
struct protocompiler *); \
|
|
int makeident2(tag,_match)(Expr *, DataStream *, \
|
|
struct protostack *, Expr *); \
|
|
int makeident2(tag,_fetch)(struct protofield *, DataStream *, \
|
|
struct protostack *, Expr *); \
|
|
void makeident2(tag,_decode)(DataStream *, struct protostack *, \
|
|
struct packetview *); \
|
|
Protocol makeident2(tag,_proto) = { \
|
|
name, constrlen(name), title, id, order, maxhdrlen, discrim, \
|
|
makeident2(tag,_init), \
|
|
makeident2(tag,_setopt), \
|
|
makeident2(tag,_embed), \
|
|
makeident2(tag,_resolve), \
|
|
makeident2(tag,_compile), \
|
|
makeident2(tag,_match), \
|
|
makeident2(tag,_fetch), \
|
|
makeident2(tag,_decode), \
|
|
flags, numopts, optdesc, xdrstate, \
|
|
}
|
|
|
|
/*
|
|
* Shorter macros to define protocols.
|
|
*/
|
|
#define DefineBranchProtocol(tag,name,title,id,order,maxhdrlen,discrim) \
|
|
DefineProtocol(tag,name,title,id,order,maxhdrlen,discrim,0,0,0,0)
|
|
|
|
#define DefineLeafProtocol(tag,name,title,id,order,maxhdrlen) \
|
|
DefineProtocol(tag,name,title,id,order,maxhdrlen,0,0,0,0,0)
|
|
|
|
/*
|
|
* Macros to call protocol operations.
|
|
*/
|
|
#define pr_init(pr) ((*(pr)->prop_init)())
|
|
#define pr_setopt(pr, id, val) ((*(pr)->prop_setopt)(id, val))
|
|
#define pr_embed(pr, npr, type, qual) ((*(pr)->prop_embed)(npr, type, qual))
|
|
#define pr_resolve(pr, str, len, sn) ((*(pr)->prop_resolve)(str, len, sn))
|
|
#define pr_compile(pr,pf,mex,tex,pc) ((*(pr)->prop_compile)(pf,mex,tex,pc))
|
|
#define pr_match(pr, pex, ds, ps, rex) ((*(pr)->prop_match)(pex, ds, ps, rex))
|
|
#define pr_fetch(pr, pf, ds, ps, rex) ((*(pr)->prop_fetch)(pf, ds, ps, rex))
|
|
#define pr_decode(pr, ds, ps, pv) ((*(pr)->prop_decode)(ds, ps, pv))
|
|
|
|
/*
|
|
* Protocol flags used by generic routines to control operation usage.
|
|
*/
|
|
#define PR_COMPILETEST 0x0001 /* compile all test expressions */
|
|
#define PR_EMBEDCACHED 0x0002 /* embed transiently-nested protocol */
|
|
#define PR_MATCHNOTIFY 0x0004 /* notify protocol when matched */
|
|
#define PR_DECODESTALE 0x0008 /* decode stale nested protocol */
|
|
|
|
/*
|
|
* Protocol scope operations.
|
|
*/
|
|
#define pr_lookupsym(pr, name, namlen) \
|
|
sc_lookupsym(&(pr)->pr_scope, name, namlen)
|
|
#define pr_addsym(pr, name, namlen, type) \
|
|
sc_addsym(&(pr)->pr_scope, name, namlen, type)
|
|
#define pr_deletesym(pr, name, namlen) \
|
|
sc_deletesym(&(pr)->pr_scope, name, namlen)
|
|
#define pr_addaddress(pr, name, namlen, addr, addrlen) \
|
|
sc_addaddress(&(pr)->pr_scope, name, namlen, addr, addrlen)
|
|
#define pr_addnumber(pr, name, namlen, val) \
|
|
sc_addnumber(&(pr)->pr_scope, name, namlen, val)
|
|
#define pr_addmacro(pr, name, namlen, def, deflen, src) \
|
|
sc_addmacro(&(pr)->pr_scope, name, namlen, def, deflen, src)
|
|
#define pr_addfunction(pr, name, namlen, func, nargs, desc) \
|
|
sc_addfunction(&(pr)->pr_scope, name, namlen, func, nargs, desc)
|
|
|
|
void sc_addaddress(Scope *, char *, int, char *, int);
|
|
void sc_addnumber(Scope *, char *, int, long);
|
|
void sc_addmacro(Scope *, char *, int, char *, int, ExprSource *);
|
|
void sc_addfunction(Scope *, char *, int, int (*)(), int, char *);
|
|
|
|
/*
|
|
* Generic protocol operations. Initprotocols raises an exception if
|
|
* any protocol module cannot be initialized. Possible errors include
|
|
* misordered or cyclic protocol dependencies, and invalid protocol
|
|
* field descriptors.
|
|
*/
|
|
struct protomacro;
|
|
|
|
void initprotocols(void);
|
|
Protocol *findprotobyname(char *, int);
|
|
Protocol *findprotobyid(unsigned int);
|
|
int pr_register(Protocol *, struct protofield *, int, int);
|
|
int pr_nest(Protocol *, int, long, struct protomacro *, int);
|
|
int pr_nestqual(Protocol *, int, long, long, struct protomacro *,
|
|
int);
|
|
int pr_unnest(Protocol *, int, long);
|
|
int pr_unnestqual(Protocol *, int, long, long);
|
|
int pr_test(Protocol *, Expr *, struct snooppacket *, int,
|
|
struct snooper *);
|
|
int pr_eval(Protocol *, Expr *, struct snooppacket *, int,
|
|
struct snooper *, ExprError *, Expr *);
|
|
|
|
/*
|
|
* This function is called by various protocols' match operations to skip
|
|
* the current (matched) component in a protocol path expression and then
|
|
* to evaluate the remaining components.
|
|
*/
|
|
int ex_match(Expr *, DataStream *, struct protostack *, Expr *);
|
|
|
|
/*
|
|
* Macros to call protocol and scope operations with constant string names.
|
|
*/
|
|
#define findprotobyconstname(name) \
|
|
findprotobyname(name, constrlen(name))
|
|
#define pr_addconstaddress(pr, name, addr, addrlen) \
|
|
pr_addaddress(pr, name, constrlen(name), addr, addrlen)
|
|
#define pr_addconstnumber(pr, name, val) \
|
|
pr_addnumber(pr, name, constrlen(name), val)
|
|
#define pr_addconstmacro(pr, name, def) \
|
|
pr_addmacro(pr, name, constrlen(name), def, constrlen(def), 0)
|
|
#define pr_addconstfunction(pr, name, func, nargs, desc) \
|
|
pr_addfunction(pr, name, constrlen(name), func, nargs, desc)
|
|
|
|
/*
|
|
* Protocol field descriptor, passed in a vector to pr_register and added
|
|
* to the registered protocol's scope. If pf_size is PF_VARIABLE, then
|
|
* pf_off contains a protocol-specific cookie. If pf_size is negative,
|
|
* its 2's-complement is the number of bits in the field, and pf_off is
|
|
* the bit offset from protocol origin.
|
|
*
|
|
* If a fixed (bit or byte) protofield passed to pr_register has a negative
|
|
* pf_off, pr_register will compute its offset by summing prior field sizes
|
|
* with the last field with a non-negative offset, or with zero if all prior
|
|
* fields in the vector had negative offsets. Bit fields must sum to a
|
|
* byte-congruent size and offset.
|
|
*/
|
|
#define PF_VARIABLE 0
|
|
|
|
typedef struct protofield {
|
|
char *pf_name; /* field name string */
|
|
int pf_namlen; /* name length */
|
|
char *pf_title; /* lengthy name string */
|
|
int pf_id; /* field identifier code */
|
|
void *pf_data; /* type specific data */
|
|
int pf_size; /* bitsize if <0, byte if >0 */
|
|
int pf_off; /* offset in bits or bytes */
|
|
enum exop pf_type; /* expression type */
|
|
int pf_level; /* viewing detail level */
|
|
} ProtoField;
|
|
|
|
#define pf_cookie pf_off
|
|
#define pf_extendhow(pf) ((enum dsextendhow)(unsigned long)(pf)->pf_data)
|
|
#define pf_element(pf) ((ProtoField *) (pf)->pf_data)
|
|
#define pf_struct(pf) ((ProtoStruct *) (pf)->pf_data)
|
|
|
|
/*
|
|
* Static initializer macros for variable, byte, bit, and int-typed fields.
|
|
* Names must be string constants or char arrays of known size.
|
|
* PFI_VAR variable field
|
|
* PFI_BYTE fixed-length byte string field
|
|
* PFI_ADDR 1- to 8-byte address field
|
|
* PFI_SBIT, PFI_UBIT signed/unsigned bit field
|
|
* PFI_SINT, PFI_UINT signed/unsigned int field
|
|
* PFI_ARRAY, PFI_STRUCT array or structure field
|
|
*/
|
|
#define PFI(name, title, id, data, size, off, type, level) \
|
|
{ name, constrlen(name), title, (int) id, (void *) data, size, off, \
|
|
type, level }
|
|
|
|
#define PFI_VAR(name, title, id, cookie, level) \
|
|
PFI(name, title, id, DS_ZERO_EXTEND, PF_VARIABLE, cookie, EXOP_STRING, \
|
|
level)
|
|
#define PFI_BYTE(name, title, id, size, level) \
|
|
PFI(name, title, id, DS_ZERO_EXTEND, size, -1, EXOP_STRING, level)
|
|
#define PFI_ADDR(name, title, id, size, level) \
|
|
PFI(name, title, id, DS_ZERO_EXTEND, size, -1, EXOP_ADDRESS, level)
|
|
|
|
#define PFI_BIT(name, title, id, extendhow, bitsize, level) \
|
|
PFI(name, title, id, extendhow, -(bitsize), -1, EXOP_NUMBER, level)
|
|
#define PFI_SBIT(name, title, id, bitsize, level) \
|
|
PFI_BIT(name, title, id, DS_SIGN_EXTEND, bitsize, level)
|
|
#define PFI_UBIT(name, title, id, bitsize, level) \
|
|
PFI_BIT(name, title, id, DS_ZERO_EXTEND, bitsize, level)
|
|
|
|
#define PFI_INT(name, title, id, extendhow, type, level) \
|
|
PFI(name, title, id, extendhow, sizeof(type), -1, EXOP_NUMBER, level)
|
|
#define PFI_SINT(name, title, id, type, level) \
|
|
PFI_INT(name, title, id, DS_SIGN_EXTEND, type, level)
|
|
#define PFI_UINT(name, title, id, type, level) \
|
|
PFI_INT(name, title, id, DS_ZERO_EXTEND, type, level)
|
|
|
|
#define PFI_ARRAY(name, title, id, type, dim, level) \
|
|
PFI(name, title, id, type, dim, -1, EXOP_ARRAY, level)
|
|
#define PFI_STRUCT(name, title, id, struct, level) \
|
|
PFI(name, title, id, struct, 0, -1, EXOP_STRUCT, level)
|
|
|
|
#define pr_findfield(pr, pfid) sc_findfield(&(pr)->pr_scope, pfid)
|
|
|
|
ProtoField *sc_findfield(Scope *, int); /* XXXbe */
|
|
|
|
/*
|
|
* Protocol structure descriptor.
|
|
*/
|
|
typedef struct protostruct {
|
|
/* statically initialized members */
|
|
char *pst_name; /* struct tag */
|
|
ProtoField *pst_fields; /* array of member fields */
|
|
int pst_numfields; /* number of members */
|
|
/* dynamically initialized members */
|
|
ProtoField *pst_parent; /* this struct's field */
|
|
Scope pst_scope; /* symbol table */
|
|
} ProtoStruct;
|
|
|
|
#define PSI(name, fields) { name, fields, lengthof(fields), }
|
|
|
|
/*
|
|
* Protocol option descriptor. Those protocols that implement pr_setopt
|
|
* should define an initialized vector of descriptors and pass it to their
|
|
* DefineProtocol calls.
|
|
*/
|
|
typedef struct protoptdesc {
|
|
char *pod_name; /* option name */
|
|
int pod_id; /* identification code */
|
|
char *pod_desc; /* brief description */
|
|
} ProtOptDesc;
|
|
|
|
#define POD(name, id, desc) { name, (int) id, desc }
|
|
|
|
ProtOptDesc *pr_findoptdesc(Protocol *, const char *);
|
|
|
|
/*
|
|
* Protocol macro, passed in a vector to pr_nest and defined in the
|
|
* encapsulating protocol's scope.
|
|
*/
|
|
typedef struct protomacro {
|
|
char *pm_name; /* protocol macro name */
|
|
int pm_namlen; /* name string length */
|
|
char *pm_def; /* and defined value */
|
|
int pm_deflen; /* def string length */
|
|
} ProtoMacro;
|
|
|
|
#define PMI(name, def) { name, constrlen(name), def, constrlen(def) }
|
|
|
|
#define pr_addmacros(pr, pm, npm) \
|
|
sc_addmacros(&(pr)->pr_scope, pm, npm)
|
|
|
|
void sc_addmacros(Scope *, ProtoMacro *, int);
|
|
|
|
/*
|
|
* Protocol function descriptor, for multiple function definition driven by
|
|
* a list of descriptors. If the function takes arguments, pfd_desc should
|
|
* end with an '@' followed by a comma-separated formal argument name list.
|
|
*/
|
|
typedef struct protofuncdesc {
|
|
char *pfd_name; /* function name */
|
|
int pfd_namlen; /* name string length */
|
|
int (*pfd_func)(); /* function pointer */
|
|
int pfd_nargs; /* number of arguments */
|
|
char *pfd_desc; /* brief description */
|
|
} ProtoFuncDesc;
|
|
|
|
#define PFD(name, func, nargs, desc) \
|
|
{ name, constrlen(name), func, nargs, desc }
|
|
|
|
#define pr_addfunctions(pr, pfd, npfd) \
|
|
sc_addfunctions(&(pr)->pr_scope, pfd, npfd)
|
|
|
|
void sc_addfunctions(Scope *, ProtoFuncDesc *, int);
|
|
|
|
/*
|
|
* Snoop filter compilation uses two datastreams, to encode mask bits
|
|
* and field values to match.
|
|
*/
|
|
typedef struct protocompiler {
|
|
unsigned short *pc_errflags; /* pointer to snoop error flags */
|
|
DataStream pc_mask; /* encoder for snoopfilter mask */
|
|
DataStream pc_match; /* encoder for fields to match */
|
|
ExprError *pc_error; /* compiler error report */
|
|
} ProtoCompiler;
|
|
|
|
#define PC_ALLINTBITS (-1L) /* mask to match all bits in any int */
|
|
#define PC_ALLBYTES ((char *) 0) /* exact mask for pc_bytes */
|
|
|
|
#define pc_loc(pc) ds_tell(&(pc)->pc_mask)
|
|
|
|
void pc_init(ProtoCompiler *, struct snoopfilter *, int,
|
|
enum dsbyteorder, unsigned short *,
|
|
ExprError *);
|
|
void pc_stop(ProtoCompiler *);
|
|
enum dsbyteorder pc_setbyteorder(ProtoCompiler *, enum dsbyteorder);
|
|
int pc_skipbytes(ProtoCompiler *, int);
|
|
int pc_skipbits(ProtoCompiler *, int);
|
|
int pc_byte(ProtoCompiler *, char, char);
|
|
int pc_bytes(ProtoCompiler *, char *, char *, int);
|
|
int pc_bits(ProtoCompiler *, long, long, int);
|
|
int pc_short(ProtoCompiler *, short, short);
|
|
int pc_long(ProtoCompiler *, long, long);
|
|
int pc_int(ProtoCompiler *, long, long, int);
|
|
int pc_intfield(ProtoCompiler *, ProtoField *, long,
|
|
long, int);
|
|
int pc_bytefield(ProtoCompiler *, ProtoField *, char *,
|
|
char *, int);
|
|
int pc_intmask(ProtoCompiler *, Expr *, long *);
|
|
void pc_error(ProtoCompiler *, Expr *, char *);
|
|
void pc_badop(ProtoCompiler *, Expr *);
|
|
|
|
/*
|
|
* Default or no-op stubs for use by top-layer and simple protocols.
|
|
* setopt, resolve, and match return 0
|
|
* embed does nothing
|
|
* compile returns ET_COMPLEX, to halt snoop filter compilation
|
|
* fetch calls ds_field
|
|
*/
|
|
int pr_stub_setopt(int, char *);
|
|
void pr_stub_embed(Protocol *, long, long);
|
|
Expr *pr_stub_resolve(char *, int, struct snooper *);
|
|
ExprType pr_stub_compile(ProtoField *, Expr *, Expr *, ProtoCompiler *);
|
|
int pr_stub_match(Expr *, DataStream *, struct protostack *, Expr *);
|
|
int pr_stub_fetch(ProtoField *, DataStream *, struct protostack *,
|
|
Expr *);
|
|
|
|
#endif
|