Index: stable/3/sys/netgraph/ng_parse.h =================================================================== --- stable/3/sys/netgraph/ng_parse.h (revision 54066) +++ stable/3/sys/netgraph/ng_parse.h (revision 54067) @@ -1,388 +1,507 @@ /* * ng_parse.h * * Copyright (c) 1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Archie Cobbs * * $Whistle: ng_parse.h,v 1.2 1999/11/29 01:43:48 archie Exp $ * $FreeBSD$ */ #ifndef _NETGRAPH_PARSE_H_ #define _NETGRAPH_PARSE_H_ /* This defines a library of routines for converting between various C language types in binary form and ASCII strings. Types are user - definable. Several pre-defined types are supplied, for some - common C types: structures, variable and fixed length arrays, - integer types, variable and fixed length strings, IP addresses, - etc. + definable. Several pre-defined types are supplied, for some common + C types: structures, variable and fixed length arrays, integer types, + variable and fixed length strings, IP addresses, etc. + A netgraph node type may provide a list of types that correspond to + the structures it expects to send and receive in the arguments field + of a control message. This allows these messages to be converted + between their native binary form and the corresponding ASCII form. + + A future use of the ASCII form may be for inter-machine communication + of control messages, because the ASCII form is machine independent + whereas the native binary form is not. + Syntax ------ Structures: '{' [ = ... ] '}' Omitted fields have their default values by implication. The order in which the fields are specified does not matter. Arrays: '[' [ [index=] ... ] ']' Element value may be specified with or without the "=" prefix; If omitted, the index after the previous element is used. Omitted fields have their default values by implication. Strings: "foo bar blah\r\n" That is, strings are specified just like C strings. The usual backslash escapes are accepted. - Other simple types have their obvious ASCII forms. + Other simple types (integers, IP addresses) have their obvious forms. Example ------- - Structure Binary (big endian) - --------- ------------------- + Suppose we have a netgraph command that takes as an argument + a 'struct foo' shown below. Here is an example of a possible + value for the structure, and the corresponding ASCII encoding + of that value: - struct foo { - struct in_addr ip; 03 03 03 03 - int bar; 00 00 00 00 - u_char num; 02 00 - short ary[0]; 00 05 00 00 00 0a - }; + Structure Binary value + --------- ------------ - ASCII form: "{ ip=3.3.3.3 num=3 ary=[ 5 2=10 ] }" + struct foo { + struct in_addr ip; 01 02 03 04 + int bar; 00 00 00 00 + char label[8]; 61 62 63 0a 00 00 00 00 + u_char alen; 03 00 + short ary[0]; 05 00 00 00 0a 00 + }; - Note that omitted fields or array elements get their default values - ("bar" and ary[2]), and that the alignment is handled automatically - (the extra 00 byte after "num"). + ASCII value + ----------- + { ip=1.2.3.4 label="abc\n" alen=3 ary=[ 5 2=10 ] } + + Note that omitted fields and array elements get their default + values ("bar" and ary[2]), and that the alignment is handled + automatically (the extra 00 byte after "num"). Also, since byte + order and alignment are inherently machine dependent, so is this + conversion process. The above example shows an x86 (little + endian) encoding. Also the above example is tricky because the + structure is variable length, depending on 'alen', the number of + elements in the array 'ary'. + + Here is how one would define a parse type for the above structure, + subclassing the pre-defined types below. We construct the type in + a 'bottom up' fashion, defining each field's type first, then the + type for the whole structure ('//' comments used to avoid breakage). + + // Super-type info for 'label' field + struct ng_parse_fixedsstring_info foo_label_info = { 8 }; + + // Parse type for 'label' field + struct ng_parse_type foo_label_type = { + &ng_parse_fixedstring_type // super-type + &foo_label_info // super-type info + }; + + #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) + + // Function to compute the length of the array 'ary', which + // is variable length, depending on the previous field 'alen'. + // Upon entry 'buf' will be pointing at &ary[0]. + int + foo_ary_getLength(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) + { + const struct foo *f; + + f = (const struct foo *)(buf - OFFSETOF(struct foo, ary)); + return f->alen; + } + + // Super-type info for 'ary' field + struct ng_parse_array_info foo_ary_info = { + &ng_parse_int16_type, // element type + &foo_ary_getLength // func to get array length + } + + // Parse type for 'ary' field + struct ng_parse_type foo_ary_type = { + &ng_parse_array_type, // super-type + &foo_ary_info // super-type info + }; + + // Super-type info for struct foo + struct ng_parse_struct_info foo_fields = { + { "ip", &ng_parse_ipaddr_type }, + { "bar", &ng_parse_int32_type }, + { "label", &foo_label_type }, + { "alen", &ng_parse_int8_type }, + { "ary", &foo_ary_type }, + { NULL } + }; + + // Parse type for struct foo + struct ng_parse_type foo_type = { + &ng_parse_struct_type, // super-type + &foo_fields // super-type info + }; + To define a type, you can define it as a sub-type of a predefined - type, overriding some of the predefined type's methods and/or its - alignment, or define your own syntax, with the restriction that - the ASCII representation must not contain any whitespace or these - characters: { } [ ] = " + type as shown above, possibly overriding some of the predefined + type's methods, or define an entirely new syntax, with the restriction + that the ASCII representation of your type's value must not contain + any whitespace or any of these characters: { } [ ] = " + See ng_ksocket.c for an example of how to do this for 'struct sockaddr'. + See ng_parse.c to see implementations of the pre-defined types below. + */ /************************************************************************ METHODS REQUIRED BY A TYPE ************************************************************************/ /* * Three methods are required for a type. These may be given explicitly - * or, if NULL, inherited from the super-type. + * or, if NULL, inherited from the super-type. The 'getDefault' method + * is always optional; the others are required if there is no super-type. */ struct ng_parse_type; /* * Convert ASCII to binary according to the supplied type. * * The ASCII characters begin at offset *off in 'string'. The binary * representation is put into 'buf', which has at least *buflen bytes. * 'start' points to the first byte output by ng_parse() (ie, start <= buf). * * Upon return, *buflen contains the length of the new binary data, and * *off is updated to point just past the end of the parsed range of * characters, or, in the case of an error, to the offending character(s). * * Return values: * 0 Success; *buflen holds the length of the data * and *off points just past the last char parsed. * EALREADY Field specified twice * ENOENT Unknown field * E2BIG Array or character string overflow * ERANGE Output was longer than *buflen bytes * EINVAL Parse failure or other invalid content * ENOMEM Out of memory * EOPNOTSUPP Mandatory array/structure element missing */ typedef int ng_parse_t(const struct ng_parse_type *type, const char *string, int *off, const u_char *start, u_char *buf, int *buflen); /* * Convert binary to ASCII according to the supplied type. * * The results are put into 'buf', which is at least buflen bytes long. * *off points to the current byte in 'data' and should be updated * before return to point just past the last byte unparsed. * * Returns: * 0 Success * ERANGE Output was longer than buflen bytes */ typedef int ng_unparse_t(const struct ng_parse_type *type, const u_char *data, int *off, char *buf, int buflen); /* * Compute the default value according to the supplied type. * * Store the result in 'buf', which is at least *buflen bytes long. * Upon return *buflen contains the length of the output. * * Returns: * 0 Success * ERANGE Output was longer than *buflen bytes * EOPNOTSUPP Default value is not specified for this type */ typedef int ng_getDefault_t(const struct ng_parse_type *type, const u_char *start, u_char *buf, int *buflen); /* * Return the alignment requirement of this type. Zero is same as one. */ typedef int ng_getAlign_t(const struct ng_parse_type *type); /************************************************************************ TYPE DEFINITION ************************************************************************/ /* * This structure describes a type, which may be a sub-type of another - * type by pointing to it with 'supertype' and omitting one or more methods. + * type by pointing to it with 'supertype' and possibly omitting methods. + * Typically the super-type requires some type-specific info, which is + * supplied by the 'info' field. + * + * The 'private' field is ignored by all of the pre-defined types. + * Sub-types may use it as they see fit. + * + * The 'getDefault' method may always be omitted (even if there is no + * super-type), which means the value for any item of this type must + * always be explicitly given. */ struct ng_parse_type { const struct ng_parse_type *supertype; /* super-type, if any */ const void *info; /* type-specific info */ void *private; /* client private info */ ng_parse_t *parse; /* parse method */ ng_unparse_t *unparse; /* unparse method */ ng_getDefault_t *getDefault; /* get default value method */ ng_getAlign_t *getAlign; /* get alignment */ }; /************************************************************************ PRE-DEFINED TYPES ************************************************************************/ /* - * Structures + * STRUCTURE TYPE * + * This type supports arbitrary C structures. The normal field alignment + * rules for the local machine are applied. Fields are always parsed in + * field order, no matter what order they are listed in the ASCII string. + * * Default value: Determined on a per-field basis * Additional info: struct ng_parse_struct_info * */ extern const struct ng_parse_type ng_parse_struct_type; /* Each field has a name, type, and optional alignment override. If the override is non-zero, the alignment is determined from the field type. Note: add an extra struct ng_parse_struct_field with name == NULL to indicate the end of the list. */ struct ng_parse_struct_info { struct ng_parse_struct_field { const char *name; /* field name */ const struct ng_parse_type *type; /* field type */ int alignment; /* override alignment */ } fields[0]; }; /* - * Fixed length arrays + * FIXED LENGTH ARRAY TYPE * - * Default value: See below + * This type supports fixed length arrays, having any element type. + * + * Default value: As returned by getDefault for each index * Additional info: struct ng_parse_fixedarray_info * */ extern const struct ng_parse_type ng_parse_fixedarray_type; -typedef int ng_parse_array_getLength_t(const struct ng_parse_type *type, - const u_char *start, const u_char *buf); +/* + * Get the default value for the element at index 'index'. This method + * may be NULL, in which case the default value is computed from the + * element type. Otherwise, it should fill in the default value at *buf + * (having size *buflen) and update *buflen to the length of the filled-in + * value before return. If there is not enough routine return ERANGE. + */ typedef int ng_parse_array_getDefault_t(const struct ng_parse_type *type, int index, const u_char *start, u_char *buf, int *buflen); -/* The 'getDefault' method may be NULL, in which case the default value - is computed from the element type. If not, it should fill in the - default value at *buf (having size *buflen) and update *buflen to the - length of the filled-in value before return. */ struct ng_parse_fixedarray_info { const struct ng_parse_type *elementType; int length; ng_parse_array_getDefault_t *getDefault; }; /* - * Variable length arrays + * VARIABLE LENGTH ARRAY TYPE * + * Same as fixed length arrays, except that the length is determined + * by a function instead of a constant value. + * * Default value: Same as with fixed length arrays * Additional info: struct ng_parse_array_info * */ extern const struct ng_parse_type ng_parse_array_type; +/* + * Return the length of the array. If the array is a field in a structure, + * all prior fields are guaranteed to be filled in already. Upon entry, + * 'start' is equal to the first byte parsed in this run, while 'buf' points + * to the first element of the array to be filled in. + */ +typedef int ng_parse_array_getLength_t(const struct ng_parse_type *type, + const u_char *start, const u_char *buf); + struct ng_parse_array_info { const struct ng_parse_type *elementType; ng_parse_array_getLength_t *getLength; ng_parse_array_getDefault_t *getDefault; }; /* - * Arbitrary length strings + * ARBITRARY LENGTH STRING TYPE * + * For arbirary length, NUL-terminated strings. + * * Default value: Empty string * Additional info: None required */ extern const struct ng_parse_type ng_parse_string_type; /* - * Bounded length strings. These are strings that have a fixed-size - * buffer, and always include a terminating NUL character. + * BOUNDED LENGTH STRING TYPE * + * These are strings that have a fixed-size buffer, and always include + * a terminating NUL character. + * * Default value: Empty string * Additional info: struct ng_parse_fixedsstring_info * */ extern const struct ng_parse_type ng_parse_fixedstring_type; struct ng_parse_fixedsstring_info { int bufSize; /* size of buffer (including NUL) */ }; /* - * Some commonly used bounded length string types + * COMMONLY USED BOUNDED LENGTH STRING TYPES */ extern const struct ng_parse_type ng_parse_nodebuf_type; /* NG_NODELEN + 1 */ extern const struct ng_parse_type ng_parse_hookbuf_type; /* NG_HOOKLEN + 1 */ extern const struct ng_parse_type ng_parse_pathbuf_type; /* NG_PATHLEN + 1 */ extern const struct ng_parse_type ng_parse_typebuf_type; /* NG_TYPELEN + 1 */ extern const struct ng_parse_type ng_parse_cmdbuf_type; /* NG_CMDSTRLEN + 1 */ /* - * Integer types + * INTEGER TYPES * * Default value: 0 * Additional info: None required */ extern const struct ng_parse_type ng_parse_int8_type; extern const struct ng_parse_type ng_parse_int16_type; extern const struct ng_parse_type ng_parse_int32_type; extern const struct ng_parse_type ng_parse_int64_type; /* - * IP address type + * IP ADDRESS TYPE * * Default value: 0.0.0.0 * Additional info: None required */ extern const struct ng_parse_type ng_parse_ipaddr_type; /* - * Variable length byte array. The bytes are displayed in hex. - * ASCII form may be either an array of bytes or a string constant, - * in which case the array is zero-filled after the string bytes. + * VARIABLE LENGTH BYTE ARRAY TYPE * + * The bytes are displayed in hex. The ASCII form may be either an + * array of bytes or a string constant, in which case the array is + * zero-filled after the string bytes. + * * Default value: All bytes are zero * Additional info: ng_parse_array_getLength_t * */ extern const struct ng_parse_type ng_parse_bytearray_type; /* - * Netgraph control message type + * NETGRAPH CONTROL MESSAGE TYPE + * + * This is the parse type for a struct ng_mesg. * * Default value: All fields zero * Additional info: None required */ extern const struct ng_parse_type ng_parse_ng_mesg_type; /************************************************************************ CONVERSTION AND PARSING ROUTINES ************************************************************************/ /* Tokens for parsing structs and arrays */ enum ng_parse_token { T_LBRACE, /* '{' */ T_RBRACE, /* '}' */ T_LBRACKET, /* '[' */ T_RBRACKET, /* ']' */ T_EQUALS, /* '=' */ T_STRING, /* string in double quotes */ T_ERROR, /* error parsing string in double quotes */ T_WORD, /* anything else containing no whitespace */ T_EOF, /* end of string reached */ }; /* * See typedef ng_parse_t for definition */ extern int ng_parse(const struct ng_parse_type *type, const char *string, int *off, u_char *buf, int *buflen); /* * See typedef ng_unparse_t for definition (*off assumed to be zero). */ extern int ng_unparse(const struct ng_parse_type *type, const u_char *data, char *buf, int buflen); /* * See typedef ng_getDefault_t for definition */ extern int ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen); /* * Parse a token: '*startp' is the offset to start looking. Upon * successful return, '*startp' equals the beginning of the token * and '*lenp' the length. If error, '*startp' points at the * offending character(s). */ extern enum ng_parse_token ng_parse_get_token(const char *s, int *startp, int *lenp); /* * Like above, but specifically for getting a string token and returning * the string value. The string token must be enclosed in double quotes * and the normal C backslash escapes are recognized. The caller must * eventually free() the returned result. Returns NULL if token is * not a string token, or parse or other error. */ extern char *ng_get_string_token(const char *s, int *startp, int *lenp); /* * Convert a raw string into a doubly-quoted string including any * necessary backslash escapes. Caller must free the result. * Returns NULL if ENOMEM. */ extern char *ng_encode_string(const char *s); #endif /* _NETGRAPH_PARSE_H_ */ Index: stable/3/sys/netgraph/ng_sample.c =================================================================== --- stable/3/sys/netgraph/ng_sample.c (revision 54066) +++ stable/3/sys/netgraph/ng_sample.c (revision 54067) @@ -1,441 +1,468 @@ /* * ng_sample.c * * Copyright (c) 1996-1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Julian Elischer * * $FreeBSD$ * $Whistle: ng_sample.c,v 1.13 1999/11/01 09:24:52 julian Exp $ */ #include #include #include #include #include +#include #include #include #include +#include #include #include /* * This section contains the netgraph method declarations for the * sample node. These methods define the netgraph 'type'. */ static ng_constructor_t ng_xxx_constructor; static ng_rcvmsg_t ng_xxx_rcvmsg; static ng_shutdown_t ng_xxx_rmnode; static ng_newhook_t ng_xxx_newhook; static ng_connect_t ng_xxx_connect; static ng_rcvdata_t ng_xxx_rcvdata; /* note these are both ng_rcvdata_t */ static ng_rcvdata_t ng_xxx_rcvdataq; /* note these are both ng_rcvdata_t */ static ng_disconnect_t ng_xxx_disconnect; +/* Parse type for struct ngxxxstat */ +static const struct ng_parse_struct_info + ng_xxx_stat_type_info = NG_XXX_STATS_TYPE_INFO; +static const struct ng_parse_type ng_xxx_stat_type = { + &ng_parse_struct_type, + &ng_xxx_stat_type_info +}; + +/* List of commands and how to convert arguments to/from ASCII */ +static const struct ng_cmdlist ng_xxx_cmdlist[] = { + { + NGM_XXX_COOKIE, + NGM_XXX_GET_STATUS, + "getstatus", + NULL, + &ng_xxx_stat_type, + }, + { + NGM_XXX_COOKIE, + NGM_XXX_SET_FLAG, + "setflag", + &ng_parse_int32_type, + NULL + }, + { 0 } +}; + /* Netgraph node type descriptor */ static struct ng_type typestruct = { NG_VERSION, NG_XXX_NODE_TYPE, NULL, ng_xxx_constructor, ng_xxx_rcvmsg, ng_xxx_rmnode, ng_xxx_newhook, NULL, ng_xxx_connect, ng_xxx_rcvdata, ng_xxx_rcvdataq, ng_xxx_disconnect, - NULL + ng_xxx_cmdlist }; NETGRAPH_INIT(xxx, &typestruct); /* Information we store for each hook on each node */ struct XXX_hookinfo { int dlci; /* The DLCI it represents, -1 == downstream */ int channel; /* The channel representing this DLCI */ hook_p hook; }; /* Information we store for each node */ struct XXX { struct XXX_hookinfo channel[XXX_NUM_DLCIS]; struct XXX_hookinfo downstream_hook; node_p node; /* back pointer to node */ hook_p debughook; u_int packets_in; /* packets in from downstream */ u_int packets_out; /* packets out towards downstream */ u_int32_t flags; }; typedef struct XXX *xxx_p; /* * Allocate the private data structure and the generic node * and link them together. * * ng_make_node_common() returns with a generic node struct * with a single reference for us.. we transfer it to the * private structure.. when we free the private struct we must * unref the node so it gets freed too. * * If this were a device node than this work would be done in the attach() * routine and the constructor would return EINVAL as you should not be able * to creatednodes that depend on hardware (unless you can add the hardware :) */ static int ng_xxx_constructor(node_p *nodep) { xxx_p privdata; int i, error; /* Initialize private descriptor */ MALLOC(privdata, xxx_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK); if (privdata == NULL) return (ENOMEM); bzero(privdata, sizeof(struct XXX)); for (i = 0; i < XXX_NUM_DLCIS; i++) { privdata->channel[i].dlci = -2; privdata->channel[i].channel = i; } /* Call the 'generic' (ie, superclass) node constructor */ if ((error = ng_make_node_common(&typestruct, nodep))) { FREE(privdata, M_NETGRAPH); return (error); } /* Link structs together; this counts as our one reference to *nodep */ (*nodep)->private = privdata; privdata->node = *nodep; return (0); } /* * Give our ok for a hook to be added... * If we are not running this might kick a device into life. * Possibly decode information out of the hook name. * Add the hook's private info to the hook structure. * (if we had some). In this example, we assume that there is a * an array of structs, called 'channel' in the private info, * one for each active channel. The private * pointer of each hook points to the appropriate XXX_hookinfo struct * so that the source of an input packet is easily identified. * (a dlci is a frame relay channel) */ static int ng_xxx_newhook(node_p node, hook_p hook, const char *name) { const xxx_p xxxp = node->private; const char *cp; - char c = '\0'; - int digits = 0; int dlci = 0; int chan; #if 0 /* Possibly start up the device if it's not already going */ if ((xxxp->flags & SCF_RUNNING) == 0) { ng_xxx_start_hardware(xxxp); } #endif /* Example of how one might use hooks with embedded numbers: All * hooks start with 'dlci' and have a decimal trailing channel * number up to 4 digits Use the leadin defined int he associated .h * file. */ if (strncmp(name, NG_XXX_HOOK_DLCI_LEADIN, strlen(NG_XXX_HOOK_DLCI_LEADIN)) == 0) { char *eptr; cp = name + sizeof(NG_XXX_HOOK_DLCI_LEADIN); if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) return (EINVAL); dlci = (int)strtoul(cp, &eptr, 10); if (*eptr != '\0' || dlci < 0 || dlci > 1023) return (EINVAL); /* We have a dlci, now either find it, or allocate it */ for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci == dlci) break; if (chan == XXX_NUM_DLCIS) { for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci != -2) continue; if (chan == XXX_NUM_DLCIS) return (ENOBUFS); } if (xxxp->channel[chan].hook != NULL) return (EADDRINUSE); hook->private = xxxp->channel + chan; xxxp->channel[chan].hook = hook; return (0); } else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) { /* Example of simple predefined hooks. */ /* do something specific to the downstream connection */ xxxp->downstream_hook.hook = hook; hook->private = &xxxp->downstream_hook; } else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) { /* do something specific to a debug connection */ xxxp->debughook = hook; hook->private = NULL; } else return (EINVAL); /* not a hook we know about */ return(0); } /* * Get a netgraph control message. * Check it is one we understand. If needed, send a response. * We could save the address for an async action later, but don't here. * Always free the message. * The response should be in a malloc'd region that the caller can 'free'. * A response is not required. * Theoretically you could respond defferently to old message types if * the cookie in the header didn't match what we consider to be current * (so that old userland programs could continue to work). */ static int ng_xxx_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) { const xxx_p xxxp = node->private; struct ng_mesg *resp = NULL; int error = 0; /* Deal with message according to cookie and command */ switch (msg->header.typecookie) { case NGM_XXX_COOKIE: switch (msg->header.cmd) { case NGM_XXX_GET_STATUS: { struct ngxxxstat *stats; NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (!resp) { error = ENOMEM; break; } stats = (struct ngxxxstat *) resp->data; stats->packets_in = xxxp->packets_in; stats->packets_out = xxxp->packets_out; break; } case NGM_XXX_SET_FLAG: if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } xxxp->flags = *((u_int32_t *) msg->data); break; default: error = EINVAL; /* unknown command */ break; } break; default: error = EINVAL; /* unknown cookie type */ break; } /* Take care of synchronous response, if any */ if (rptr) *rptr = resp; else if (resp) FREE(resp, M_NETGRAPH); /* Free the message and return */ FREE(msg, M_NETGRAPH); return(error); } /* * Receive data, and do something with it. * Possibly send it out on another link after processing. * Possibly do something different if it comes from different * hooks. the caller will never free m or meta, so * if we use up this data or abort we must free BOTH of these. * * If we want, we may decide to force this data to be queued and reprocessed * at the netgraph NETISR time. (at which time it will be entered using ng_xxx_rcvdataq(). */ static int ng_xxx_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) { int dlci = -2; - int error; if (hook->private) { /* - * If it's dlci 1023, requeue it so that it's handled at a lower priority. - * This is how a node decides to defer a data message. + * If it's dlci 1023, requeue it so that it's handled + * at a lower priority. This is how a node decides to + * defer a data message. */ dlci = ((struct XXX_hookinfo *) hook->private)->dlci; if (dlci == 1023) { return(ng_queue_data(hook->peer, m, meta)); } } return(ng_xxx_rcvdataq(hook, m, meta)); } /* * Always accept the data. This version of rcvdata is called from the dequeueing routine. */ static int ng_xxx_rcvdataq(hook_p hook, struct mbuf *m, meta_p meta) { const xxx_p xxxp = hook->node->private; int chan = -2; int dlci = -2; int error; if (hook->private) { dlci = ((struct XXX_hookinfo *) hook->private)->dlci; chan = ((struct XXX_hookinfo *) hook->private)->channel; if (dlci != -1) { /* If received on a DLCI hook process for this * channel and pass it to the downstream module. * Normally one would add a multiplexing header at * the front here */ /* M_PREPEND(....) ; */ /* mtod(m, xxxxxx)->dlci = dlci; */ error = ng_send_data(xxxp->downstream_hook.hook, m, meta); xxxp->packets_out++; } else { /* data came from the multiplexed link */ dlci = 1; /* get dlci from header */ /* madjust(....) *//* chop off header */ for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci == dlci) break; if (chan == XXX_NUM_DLCIS) { NG_FREE_DATA(m, meta); return (ENETUNREACH); } /* If we were called at splnet, use the following: * NG_SEND_DATA(error, otherhook, m, meta); if this * node is running at some SPL other than SPLNET * then you should use instead: error = * ng_queueit(otherhook, m, meta); m = NULL: meta = * NULL; this queues the data using the standard * NETISR system and schedules the data to be picked * up again once the system has moved to SPLNET and * the processing of the data can continue. after * these are run 'm' and 'meta' should be considered * as invalid and NG_SEND_DATA actually zaps them. */ NG_SEND_DATA(error, xxxp->channel[chan].hook, m, meta); xxxp->packets_in++; } } else { /* It's the debug hook, throw it away.. */ if (hook == xxxp->downstream_hook.hook) NG_FREE_DATA(m, meta); } return 0; } #if 0 /* * If this were a device node, the data may have been received in response * to some interrupt. * in which case it would probably look as follows: */ devintr() { meta_p meta = NULL; /* whatever metadata we might imagine goes * here */ /* get packet from device and send on */ m = MGET(blah blah) error = ng_queueit(upstream, m, meta); /* see note above in * xxx_rcvdata() */ } #endif /* 0 */ /* * Do local shutdown processing.. * If we are a persistant device, we might refuse to go away, and * we'd only remove our links and reset ourself. */ static int ng_xxx_rmnode(node_p node) { const xxx_p privdata = node->private; node->flags |= NG_INVALID; ng_cutlinks(node); #ifndef PERSISTANT_NODE ng_unname(node); node->private = NULL; ng_unref(privdata->node); FREE(privdata, M_NETGRAPH); #else privdata->packets_in = 0; /* reset stats */ privdata->packets_out = 0; node->flags &= ~NG_INVALID; /* reset invalid flag */ #endif /* PERSISTANT_NODE */ return (0); } /* * This is called once we've already connected a new hook to the other node. * It gives us a chance to balk at the last minute. */ static int ng_xxx_connect(hook_p hook) { /* be really amiable and just say "YUP that's OK by me! " */ return (0); } /* * Dook disconnection * * For this type, removal of the last link destroys the node */ static int ng_xxx_disconnect(hook_p hook) { if (hook->private) - ((struct XXX_hookinfo *) (hook->private))->hook == NULL; + ((struct XXX_hookinfo *) (hook->private))->hook = NULL; if (hook->node->numhooks == 0) ng_rmnode(hook->node); return (0); } Index: stable/3/sys/netgraph/ng_sample.h =================================================================== --- stable/3/sys/netgraph/ng_sample.h (revision 54066) +++ stable/3/sys/netgraph/ng_sample.h (revision 54067) @@ -1,75 +1,90 @@ /* * ng_sample.h * * Copyright (c) 1996-1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Julian Elischer * * $FreeBSD$ * $Whistle: ng_sample.h,v 1.3 1999/01/20 00:22:14 archie Exp $ */ #ifndef _NETGRAPH_SAMPLE_H_ #define _NETGRAPH_SAMPLE_H_ /* Node type name. This should be unique among all netgraph node types */ #define NG_XXX_NODE_TYPE "sample" /* Node type cookie. Should also be unique. This value MUST change whenever an incompatible change is made to this header file, to insure consistency. The de facto method for generating cookies is to take the output of the date command: date -u +'%s' */ #define NGM_XXX_COOKIE 915491374 /* Number of active DLCI's we can handle */ #define XXX_NUM_DLCIS 16 /* Hook names */ #define NG_XXX_HOOK_DLCI_LEADIN "dlci" #define NG_XXX_HOOK_DOWNSTREAM "downstream" #define NG_XXX_HOOK_DEBUG "debug" /* Netgraph commands understood by this node type */ enum { NGM_XXX_SET_FLAG = 1, NGM_XXX_GET_STATUS, }; /* This structure is returned by the NGM_XXX_GET_STATUS command */ struct ngxxxstat { u_int packets_in; /* packets in from downstream */ u_int packets_out; /* packets out towards downstream */ }; +/* + * This is used to define the 'parse type' for a struct ngxxxstat, which + * is bascially a description of how to convert a binary struct ngxxxstat + * to an ASCII string and back. See ng_parse.h for more info. + * + * This needs to be kept in sync with the above structure definition + */ +#define NG_XXX_STATS_TYPE_INFO { \ + { \ + { "packets_in", &ng_parse_int32_type }, \ + { "packets_out", &ng_parse_int32_type }, \ + { NULL }, \ + } \ +} + #endif /* _NETGRAPH_SAMPLE_H_ */ Index: stable/3/sys/netgraph/ng_tee.c =================================================================== --- stable/3/sys/netgraph/ng_tee.c (revision 54066) +++ stable/3/sys/netgraph/ng_tee.c (revision 54067) @@ -1,337 +1,337 @@ /* * ng_tee.c * * Copyright (c) 1996-1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications; * provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Julian Elischer * * $FreeBSD$ * $Whistle: ng_tee.c,v 1.18 1999/11/01 09:24:52 julian Exp $ */ /* * This node is like the tee(1) command and is useful for ``snooping.'' * It has 4 hooks: left, right, left2right, and right2left. Data * entering from the right is passed to the left and duplicated on * right2left, and data entering from the left is passed to the right * and duplicated on left2right. Data entering from left2right is * sent to right, and data from right2left to left. */ #include #include #include #include #include #include #include #include #include /* Per hook info */ struct hookinfo { hook_p hook; struct ng_tee_hookstat stats; }; /* Per node info */ struct privdata { node_p node; struct hookinfo left; struct hookinfo right; struct hookinfo left2right; struct hookinfo right2left; }; typedef struct privdata *sc_p; /* Netgraph methods */ static ng_constructor_t ngt_constructor; static ng_rcvmsg_t ngt_rcvmsg; static ng_shutdown_t ngt_rmnode; static ng_newhook_t ngt_newhook; static ng_rcvdata_t ngt_rcvdata; static ng_disconnect_t ngt_disconnect; /* Netgraph type descriptor */ static struct ng_type typestruct = { NG_VERSION, NG_TEE_NODE_TYPE, NULL, ngt_constructor, ngt_rcvmsg, ngt_rmnode, ngt_newhook, NULL, NULL, ngt_rcvdata, ngt_rcvdata, ngt_disconnect, NULL }; NETGRAPH_INIT(tee, &typestruct); /* * Node constructor */ static int ngt_constructor(node_p *nodep) { sc_p privdata; int error = 0; MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK); if (privdata == NULL) return (ENOMEM); bzero(privdata, sizeof(*privdata)); if ((error = ng_make_node_common(&typestruct, nodep))) { FREE(privdata, M_NETGRAPH); return (error); } (*nodep)->private = privdata; privdata->node = *nodep; return (0); } /* * Add a hook */ static int ngt_newhook(node_p node, hook_p hook, const char *name) { const sc_p sc = node->private; if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) { sc->right.hook = hook; bzero(&sc->right.stats, sizeof(sc->right.stats)); hook->private = &sc->right; } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) { sc->left.hook = hook; bzero(&sc->left.stats, sizeof(sc->left.stats)); hook->private = &sc->left; } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) { sc->right2left.hook = hook; bzero(&sc->right2left.stats, sizeof(sc->right2left.stats)); hook->private = &sc->right2left; } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) { sc->left2right.hook = hook; bzero(&sc->left2right.stats, sizeof(sc->left2right.stats)); hook->private = &sc->left2right; } else return (EINVAL); return (0); } /* * Receive a control message */ static int ngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) { const sc_p sc = node->private; struct ng_mesg *resp = NULL; int error = 0; switch (msg->header.typecookie) { case NGM_TEE_COOKIE: switch (msg->header.cmd) { case NGM_TEE_GET_STATS: { struct ng_tee_stats *stats; NG_MKRESPONSE(resp, msg, sizeof(struct ng_tee_stats), M_NOWAIT); if (resp == NULL) { error = ENOMEM; goto done; } stats = (struct ng_tee_stats *) resp->data; bcopy(&sc->right.stats, &stats->right, sizeof(stats->right)); bcopy(&sc->left.stats, &stats->left, sizeof(stats->left)); bcopy(&sc->right2left.stats, &stats->right2left, sizeof(stats->right2left)); bcopy(&sc->left2right.stats, &stats->left2right, sizeof(stats->left2right)); break; } case NGM_TEE_CLR_STATS: bzero(&sc->right.stats, sizeof(sc->right.stats)); bzero(&sc->left.stats, sizeof(sc->left.stats)); bzero(&sc->right2left.stats, sizeof(sc->right2left.stats)); bzero(&sc->left2right.stats, sizeof(sc->left2right.stats)); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } if (rptr) *rptr = resp; else if (resp) FREE(resp, M_NETGRAPH); done: FREE(msg, M_NETGRAPH); return (error); } /* * Receive data on a hook * * If data comes in the right link send a copy out right2left, and then * send the original onwards out through the left link. * Do the opposite for data coming in from the left link. * Data coming in right2left or left2right is forwarded * on through the appropriate destination hook as if it had come * from the other side. */ static int ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) { const sc_p sc = hook->node->private; struct hookinfo *const hinfo = (struct hookinfo *) hook->private; struct hookinfo *dest; struct hookinfo *dup; int error = 0; /* Which hook? */ if (hinfo == &sc->left) { dup = &sc->left2right; dest = &sc->right; } else if (hinfo == &sc->right) { dup = &sc->right2left; dest = &sc->left; } else if (hinfo == &sc->right2left) { dup = NULL; dest = &sc->left; } else if (hinfo == &sc->left2right) { dup = NULL; dest = &sc->right; } else panic("%s: no hook!", __FUNCTION__); /* Update stats on incoming hook */ hinfo->stats.inOctets += m->m_pkthdr.len; hinfo->stats.inFrames++; /* Duplicate packet and meta info if requried */ if (dup != NULL) { struct mbuf *m2; meta_p meta2; /* Copy packet */ - m2 = m_copypacket(m, M_NOWAIT); + m2 = m_dup(m, M_NOWAIT); if (m2 == NULL) { NG_FREE_DATA(m, meta); return (ENOBUFS); } /* Copy meta info */ if (meta != NULL) { MALLOC(meta2, meta_p, meta->used_len, M_NETGRAPH, M_NOWAIT); if (meta2 == NULL) { m_freem(m2); NG_FREE_DATA(m, meta); return (ENOMEM); } bcopy(meta, meta2, meta->used_len); meta2->allocated_len = meta->used_len; } else meta2 = NULL; /* Deliver duplicate */ dup->stats.outOctets += m->m_pkthdr.len; dup->stats.outFrames++; NG_SEND_DATA(error, dup->hook, m2, meta2); } /* Deliver frame out destination hook */ dest->stats.outOctets += m->m_pkthdr.len; dest->stats.outFrames++; NG_SEND_DATA(error, dest->hook, m, meta); return (0); } /* * Shutdown processing * * This is tricky. If we have both a left and right hook, then we * probably want to extricate ourselves and leave the two peers * still linked to each other. Otherwise we should just shut down as * a normal node would. * * To keep the scope of info correct the routine to "extract" a node * from two links is in ng_base.c. */ static int ngt_rmnode(node_p node) { const sc_p privdata = node->private; node->flags |= NG_INVALID; if (privdata->left.hook && privdata->right.hook) ng_bypass(privdata->left.hook, privdata->right.hook); ng_cutlinks(node); ng_unname(node); node->private = NULL; ng_unref(privdata->node); FREE(privdata, M_NETGRAPH); return (0); } /* * Hook disconnection */ static int ngt_disconnect(hook_p hook) { struct hookinfo *const hinfo = (struct hookinfo *) hook->private; KASSERT(hinfo != NULL, ("%s: null info", __FUNCTION__)); hinfo->hook = NULL; if (hook->node->numhooks == 0) ng_rmnode(hook->node); return (0); }