summaryrefslogtreecommitdiffstats
path: root/sys/netgraph
diff options
context:
space:
mode:
authorarchie <archie@FreeBSD.org>1999-11-30 02:45:32 +0000
committerarchie <archie@FreeBSD.org>1999-11-30 02:45:32 +0000
commit81fceb37a95304786f88f6611289a27c7262d394 (patch)
tree321a35b746bb34b931d0691c03f9888db83ed68b /sys/netgraph
parent9716636318d4160418baceabe7ba05ce065692fc (diff)
downloadFreeBSD-src-81fceb37a95304786f88f6611289a27c7262d394.zip
FreeBSD-src-81fceb37a95304786f88f6611289a27c7262d394.tar.gz
Add two new generic control messages, NGM_ASCII2BINARY and
NGM_BINARY2ASCII, which convert control messages to ASCII and back. This allows control messages to be sent and received in ASCII form using ngctl(8), which makes ngctl a lot more useful. This also allows all the type-specific debugging code in libnetgraph to go away -- instead, we just ask the node itself to do the ASCII translation for us. Currently, all generic control messages are supported, as well as messages associated with the following node types: async, cisco, ksocket, and ppp. See /usr/share/examples/netgraph/ngctl for an example of using this. Also give ngctl(8) the ability to print out incoming data and control messages at any time. Eventually nghook(8) may be subsumed. Several other misc. bug fixes. Reviewed by: julian
Diffstat (limited to 'sys/netgraph')
-rw-r--r--sys/netgraph/netgraph.h26
-rw-r--r--sys/netgraph/ng_UI.c3
-rw-r--r--sys/netgraph/ng_UI.h2
-rw-r--r--sys/netgraph/ng_async.c55
-rw-r--r--sys/netgraph/ng_async.h28
-rw-r--r--sys/netgraph/ng_base.c319
-rw-r--r--sys/netgraph/ng_cisco.c62
-rw-r--r--sys/netgraph/ng_cisco.h39
-rw-r--r--sys/netgraph/ng_echo.c3
-rw-r--r--sys/netgraph/ng_ether.h10
-rw-r--r--sys/netgraph/ng_frame_relay.c5
-rw-r--r--sys/netgraph/ng_hole.c3
-rw-r--r--sys/netgraph/ng_iface.c14
-rw-r--r--sys/netgraph/ng_ksocket.c557
-rw-r--r--sys/netgraph/ng_ksocket.h22
-rw-r--r--sys/netgraph/ng_lmi.c3
-rw-r--r--sys/netgraph/ng_message.h159
-rw-r--r--sys/netgraph/ng_parse.c1604
-rw-r--r--sys/netgraph/ng_parse.h388
-rw-r--r--sys/netgraph/ng_ppp.c78
-rw-r--r--sys/netgraph/ng_ppp.h48
-rw-r--r--sys/netgraph/ng_pppoe.c3
-rw-r--r--sys/netgraph/ng_rfc1490.c3
-rw-r--r--sys/netgraph/ng_rfc1490.h2
-rw-r--r--sys/netgraph/ng_sample.c3
-rw-r--r--sys/netgraph/ng_socket.c3
-rw-r--r--sys/netgraph/ng_tee.c3
-rw-r--r--sys/netgraph/ng_tty.c21
-rw-r--r--sys/netgraph/ng_vjc.c3
29 files changed, 3320 insertions, 149 deletions
diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h
index 94649e6..d693aa5 100644
--- a/sys/netgraph/netgraph.h
+++ b/sys/netgraph/netgraph.h
@@ -112,7 +112,7 @@ struct meta_field_header {
};
/* To zero out an option 'in place' set it's cookie to this */
-#define INVALID_COOKIE 865455152
+#define NGM_INVALID_COOKIE 865455152
/* This part of the metadata is always present if the pointer is non NULL */
struct ng_meta {
@@ -132,7 +132,7 @@ typedef struct ng_meta *meta_p;
/* node method definitions */
typedef int ng_constructor_t(node_p *node);
typedef int ng_rcvmsg_t(node_p node, struct ng_mesg *msg,
- const char *retaddr, struct ng_mesg **resp);
+ const char *retaddr, struct ng_mesg **resp);
typedef int ng_shutdown_t(node_p node);
typedef int ng_newhook_t(node_p node, hook_p hook, const char *name);
typedef hook_p ng_findhook_t(node_p node, const char *name);
@@ -141,12 +141,26 @@ typedef int ng_rcvdata_t(hook_p hook, struct mbuf *m, meta_p meta);
typedef int ng_disconnect_t(hook_p hook);
/*
+ * Command list -- each node type specifies the command that it knows
+ * how to convert between ASCII and binary using an array of these.
+ * The last element in the array must be a terminator with cookie=0.
+ */
+
+struct ng_cmdlist {
+ u_int32_t cookie; /* command typecookie */
+ int cmd; /* command number */
+ const char *name; /* command name */
+ const struct ng_parse_type *mesgType; /* args if !NGF_RESP */
+ const struct ng_parse_type *respType; /* args if NGF_RESP */
+};
+
+/*
* Structure of a node type
*/
struct ng_type {
- u_int32_t version; /* must equal NG_VERSION */
- const char *name; /* Unique type name */
+ u_int32_t version; /* must equal NG_VERSION */
+ const char *name; /* Unique type name */
modeventhand_t mod_event; /* Module event handler (optional) */
ng_constructor_t *constructor; /* Node constructor */
ng_rcvmsg_t *rcvmsg; /* control messages come here */
@@ -158,7 +172,9 @@ struct ng_type {
ng_rcvdata_t *rcvdataq; /* or here if been queued */
ng_disconnect_t *disconnect; /* notify on disconnect */
- /* R/W data private to the base netgraph code DON'T TOUCH!*/
+ const struct ng_cmdlist *cmdlist; /* commands we can convert */
+
+ /* R/W data private to the base netgraph code DON'T TOUCH! */
LIST_ENTRY(ng_type) types; /* linked list of all types */
int refs; /* number of instances */
};
diff --git a/sys/netgraph/ng_UI.c b/sys/netgraph/ng_UI.c
index d30005f..21a10f5 100644
--- a/sys/netgraph/ng_UI.c
+++ b/sys/netgraph/ng_UI.c
@@ -94,7 +94,8 @@ static struct ng_type typestruct = {
NULL,
ng_UI_rcvdata,
ng_UI_rcvdata,
- ng_UI_disconnect
+ ng_UI_disconnect,
+ NULL
};
NETGRAPH_INIT(UI, &typestruct);
diff --git a/sys/netgraph/ng_UI.h b/sys/netgraph/ng_UI.h
index f41e5a9..52fc362 100644
--- a/sys/netgraph/ng_UI.h
+++ b/sys/netgraph/ng_UI.h
@@ -45,7 +45,7 @@
/* Node type name and cookie */
#define NG_UI_NODE_TYPE "UI"
-#define NGM_UI_NODE_COOKIE 884639499
+#define NGM_UI_COOKIE 884639499
/* Hook names */
#define NG_UI_HOOK_DOWNSTREAM "downstream"
diff --git a/sys/netgraph/ng_async.c b/sys/netgraph/ng_async.c
index ca96dbe..4c7e3ab 100644
--- a/sys/netgraph/ng_async.c
+++ b/sys/netgraph/ng_async.c
@@ -61,6 +61,7 @@
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_async.h>
+#include <netgraph/ng_parse.h>
#include <net/ppp_defs.h>
@@ -91,7 +92,7 @@ typedef struct ng_async_private *sc_p;
#define ERROUT(x) do { error = (x); goto done; } while (0)
/* Netgraph methods */
-static ng_constructor_t nga_constructor;
+static ng_constructor_t nga_constructor;
static ng_rcvdata_t nga_rcvdata;
static ng_rcvmsg_t nga_rcvmsg;
static ng_shutdown_t nga_shutdown;
@@ -102,6 +103,55 @@ static ng_disconnect_t nga_disconnect;
static int nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
static int nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
+/* Parse type for struct ng_async_cfg */
+static const struct ng_parse_struct_info
+ nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO;
+static const struct ng_parse_type nga_config_type = {
+ &ng_parse_struct_type,
+ &nga_config_type_info
+};
+
+/* Parse type for struct ng_async_stat */
+static const struct ng_parse_struct_info
+ nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO;
+static const struct ng_parse_type nga_stats_type = {
+ &ng_parse_struct_type,
+ &nga_stats_type_info,
+};
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist nga_cmdlist[] = {
+ {
+ NGM_ASYNC_COOKIE,
+ NGM_ASYNC_CMD_SET_CONFIG,
+ "setconfig",
+ &nga_config_type,
+ NULL
+ },
+ {
+ NGM_ASYNC_COOKIE,
+ NGM_ASYNC_CMD_GET_CONFIG,
+ "getconfig",
+ NULL,
+ &nga_config_type
+ },
+ {
+ NGM_ASYNC_COOKIE,
+ NGM_ASYNC_CMD_GET_STATS,
+ "getstats",
+ NULL,
+ &nga_stats_type
+ },
+ {
+ NGM_ASYNC_COOKIE,
+ NGM_ASYNC_CMD_CLR_STATS,
+ "clrstats",
+ &nga_stats_type,
+ NULL
+ },
+ { 0 }
+};
+
/* Define the netgraph node type */
static struct ng_type typestruct = {
NG_VERSION,
@@ -115,7 +165,8 @@ static struct ng_type typestruct = {
NULL,
nga_rcvdata,
nga_rcvdata,
- nga_disconnect
+ nga_disconnect,
+ nga_cmdlist
};
NETGRAPH_INIT(async, &typestruct);
diff --git a/sys/netgraph/ng_async.h b/sys/netgraph/ng_async.h
index a91ef16..63f6e43 100644
--- a/sys/netgraph/ng_async.h
+++ b/sys/netgraph/ng_async.h
@@ -45,7 +45,7 @@
/* Type name and cookie */
#define NG_ASYNC_NODE_TYPE "async"
-#define NGM_ASYNC_COOKIE 886473718
+#define NGM_ASYNC_COOKIE 886473717
/* Hook names */
#define NG_ASYNC_HOOK_SYNC "sync" /* Sync frames */
@@ -68,6 +68,21 @@ struct ng_async_stat {
u_int32_t asyncBadCheckSums;
};
+/* Keep this in sync with the above structure definition */
+#define NG_ASYNC_STATS_TYPE_INFO { \
+ { \
+ { "syncOctets", &ng_parse_int32_type }, \
+ { "syncFrames", &ng_parse_int32_type }, \
+ { "syncOverflows", &ng_parse_int32_type }, \
+ { "asyncOctets", &ng_parse_int32_type }, \
+ { "asyncFrames", &ng_parse_int32_type }, \
+ { "asyncRunts", &ng_parse_int32_type }, \
+ { "asyncOverflows", &ng_parse_int32_type }, \
+ { "asyncBadCheckSums",&ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
/* Configuration for this node */
struct ng_async_cfg {
u_char enabled; /* Turn encoding on/off */
@@ -76,6 +91,17 @@ struct ng_async_cfg {
u_int32_t accm; /* ACCM encoding */
};
+/* Keep this in sync with the above structure definition */
+#define NG_ASYNC_CONFIG_TYPE_INFO { \
+ { \
+ { "enabled", &ng_parse_int8_type }, \
+ { "amru", &ng_parse_int16_type }, \
+ { "smru", &ng_parse_int16_type }, \
+ { "accm", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
/* Commands */
enum {
NGM_ASYNC_CMD_GET_STATS = 1, /* returns struct ng_async_stat */
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index 84cd696..7d20e80 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -62,6 +62,7 @@
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
/* List of all nodes */
static LIST_HEAD(, ng_node) nodelist;
@@ -114,6 +115,179 @@ static ng_ID_t nextID = 1;
/************************************************************************
+ Parse type definitions for generic messages
+************************************************************************/
+
+/* Handy structure parse type defining macro */
+#define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \
+static const struct ng_parse_struct_info \
+ ng_ ## lo ## _type_info = NG_GENERIC_ ## up ## _INFO args; \
+static const struct ng_parse_type ng_generic_ ## lo ## _type = { \
+ &ng_parse_struct_type, \
+ &ng_ ## lo ## _type_info \
+}
+
+DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ());
+DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ());
+DEFINE_PARSE_STRUCT_TYPE(name, NAME, ());
+DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ());
+DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ());
+DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ());
+DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type));
+
+/* Get length of an array when the length is stored as a 32 bit
+ value immediately preceeding the array -- as with struct namelist
+ and struct typelist. */
+static int
+ng_generic_list_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ return *((const u_int32_t *)(buf - 4));
+}
+
+/* Get length of the array of struct linkinfo inside a struct hooklist */
+static int
+ng_generic_linkinfo_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ const struct hooklist *hl = (const struct hooklist *)start;
+
+ return hl->nodeinfo.hooks;
+}
+
+/* Array type for a variable length array of struct namelist */
+static const struct ng_parse_array_info ng_nodeinfoarray_type_info = {
+ &ng_generic_nodeinfo_type,
+ &ng_generic_list_getLength
+};
+static const struct ng_parse_type ng_generic_nodeinfoarray_type = {
+ &ng_parse_array_type,
+ &ng_nodeinfoarray_type_info
+};
+
+/* Array type for a variable length array of struct typelist */
+static const struct ng_parse_array_info ng_typeinfoarray_type_info = {
+ &ng_generic_typeinfo_type,
+ &ng_generic_list_getLength
+};
+static const struct ng_parse_type ng_generic_typeinfoarray_type = {
+ &ng_parse_array_type,
+ &ng_typeinfoarray_type_info
+};
+
+/* Array type for array of struct linkinfo in struct hooklist */
+static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = {
+ &ng_generic_linkinfo_type,
+ &ng_generic_linkinfo_getLength
+};
+static const struct ng_parse_type ng_generic_linkinfo_array_type = {
+ &ng_parse_array_type,
+ &ng_generic_linkinfo_array_type_info
+};
+
+DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type));
+DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST,
+ (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type));
+DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES,
+ (&ng_generic_nodeinfoarray_type));
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_generic_cmds[] = {
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_SHUTDOWN,
+ "shutdown",
+ NULL,
+ NULL
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_MKPEER,
+ "mkpeer",
+ &ng_generic_mkpeer_type,
+ NULL
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_CONNECT,
+ "connect",
+ &ng_generic_connect_type,
+ NULL
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_NAME,
+ "name",
+ &ng_generic_name_type,
+ NULL
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_RMHOOK,
+ "rmhook",
+ &ng_generic_rmhook_type,
+ NULL
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_NODEINFO,
+ "nodeinfo",
+ NULL,
+ &ng_generic_nodeinfo_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_LISTHOOKS,
+ "listhooks",
+ NULL,
+ &ng_generic_hooklist_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_LISTNAMES,
+ "listnames",
+ NULL,
+ &ng_generic_listnodes_type /* same as NGM_LISTNODES */
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_LISTNODES,
+ "listnodes",
+ NULL,
+ &ng_generic_listnodes_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_LISTTYPES,
+ "listtypes",
+ NULL,
+ &ng_generic_typeinfo_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_TEXT_STATUS,
+ "textstatus",
+ NULL,
+ &ng_parse_string_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_ASCII2BINARY,
+ "ascii2binary",
+ &ng_parse_ng_mesg_type,
+ &ng_parse_ng_mesg_type
+ },
+ {
+ NGM_GENERIC_COOKIE,
+ NGM_BINARY2ASCII,
+ "binary2ascii",
+ &ng_parse_ng_mesg_type,
+ &ng_parse_ng_mesg_type
+ },
+ { 0 }
+};
+
+/************************************************************************
Node routines
************************************************************************/
@@ -1256,6 +1430,151 @@ ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
break;
}
+ case NGM_BINARY2ASCII:
+ {
+ int bufSize = 2000; /* XXX hard coded constant */
+ const struct ng_parse_type *argstype;
+ const struct ng_cmdlist *c;
+ struct ng_mesg *rp, *binary, *ascii;
+
+ /* Data area must contain a valid netgraph message */
+ binary = (struct ng_mesg *)msg->data;
+ if (msg->header.arglen < sizeof(struct ng_mesg)
+ || msg->header.arglen - sizeof(struct ng_mesg)
+ < binary->header.arglen) {
+ error = EINVAL;
+ break;
+ }
+
+ /* Get a response message with lots of room */
+ NG_MKRESPONSE(rp, msg, sizeof(*ascii) + bufSize, M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ ascii = (struct ng_mesg *)rp->data;
+
+ /* Copy binary message header to response message payload */
+ bcopy(binary, ascii, sizeof(*binary));
+
+ /* Find command by matching typecookie and command number */
+ for (c = here->type->cmdlist;
+ c != NULL && c->name != NULL; c++) {
+ if (binary->header.typecookie == c->cookie
+ && binary->header.cmd == c->cmd)
+ break;
+ }
+ if (c == NULL || c->name == NULL) {
+ for (c = ng_generic_cmds; c->name != NULL; c++) {
+ if (binary->header.typecookie == c->cookie
+ && binary->header.cmd == c->cmd)
+ break;
+ }
+ if (c->name == NULL) {
+ FREE(rp, M_NETGRAPH);
+ error = ENOSYS;
+ break;
+ }
+ }
+
+ /* Convert command name to ASCII */
+ snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr),
+ "%s", c->name);
+
+ /* Convert command arguments to ASCII */
+ argstype = (binary->header.flags & NGF_RESP) ?
+ c->respType : c->mesgType;
+ if (argstype == NULL)
+ *ascii->data = '\0';
+ else {
+ if ((error = ng_unparse(argstype,
+ (u_char *)binary->data,
+ ascii->data, bufSize)) != 0) {
+ FREE(rp, M_NETGRAPH);
+ break;
+ }
+ }
+
+ /* Return the result as struct ng_mesg plus ASCII string */
+ bufSize = strlen(ascii->data) + 1;
+ ascii->header.arglen = bufSize;
+ rp->header.arglen = sizeof(*ascii) + bufSize;
+ *resp = rp;
+ break;
+ }
+
+ case NGM_ASCII2BINARY:
+ {
+ int bufSize = 2000; /* XXX hard coded constant */
+ const struct ng_cmdlist *c;
+ const struct ng_parse_type *argstype;
+ struct ng_mesg *rp, *ascii, *binary;
+ int off;
+
+ /* Data area must contain at least a struct ng_mesg + '\0' */
+ ascii = (struct ng_mesg *)msg->data;
+ if (msg->header.arglen < sizeof(*ascii) + 1
+ || ascii->header.arglen < 1
+ || msg->header.arglen
+ < sizeof(*ascii) + ascii->header.arglen) {
+ error = EINVAL;
+ break;
+ }
+ ascii->data[ascii->header.arglen - 1] = '\0';
+
+ /* Get a response message with lots of room */
+ NG_MKRESPONSE(rp, msg, sizeof(*binary) + bufSize, M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ binary = (struct ng_mesg *)rp->data;
+
+ /* Copy ASCII message header to response message payload */
+ bcopy(ascii, binary, sizeof(*ascii));
+
+ /* Find command by matching ASCII command string */
+ for (c = here->type->cmdlist;
+ c != NULL && c->name != NULL; c++) {
+ if (strcmp(ascii->header.cmdstr, c->name) == 0)
+ break;
+ }
+ if (c == NULL || c->name == NULL) {
+ for (c = ng_generic_cmds; c->name != NULL; c++) {
+ if (strcmp(ascii->header.cmdstr, c->name) == 0)
+ break;
+ }
+ if (c->name == NULL) {
+ FREE(rp, M_NETGRAPH);
+ error = ENOSYS;
+ break;
+ }
+ }
+
+ /* Convert command name to binary */
+ binary->header.cmd = c->cmd;
+ binary->header.typecookie = c->cookie;
+
+ /* Convert command arguments to binary */
+ argstype = (binary->header.flags & NGF_RESP) ?
+ c->respType : c->mesgType;
+ if (argstype == NULL)
+ bufSize = 0;
+ else {
+ if ((error = ng_parse(argstype, ascii->data,
+ &off, (u_char *)binary->data, &bufSize)) != 0) {
+ FREE(rp, M_NETGRAPH);
+ break;
+ }
+ }
+
+ /* Return the result */
+ binary->header.arglen = bufSize;
+ rp->header.arglen = sizeof(*binary) + bufSize;
+ *resp = rp;
+ break;
+ }
+
case NGM_TEXT_STATUS:
/*
* This one is tricky as it passes the command down to the
diff --git a/sys/netgraph/ng_cisco.c b/sys/netgraph/ng_cisco.c
index cc30d3d..26898ce 100644
--- a/sys/netgraph/ng_cisco.c
+++ b/sys/netgraph/ng_cisco.c
@@ -67,6 +67,7 @@
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
#include <netgraph/ng_cisco.h>
#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
@@ -105,7 +106,7 @@ struct protoent {
struct cisco_priv {
u_long local_seq;
u_long remote_seq;
- u_long seq_retries; /* how many times we've been here throwing out
+ u_long seqRetries; /* how many times we've been here throwing out
* the same sequence number without ack */
node_p node;
struct callout_handle handle;
@@ -131,6 +132,48 @@ static int cisco_input(sc_p sc, struct mbuf *m, meta_p meta);
static void cisco_keepalive(void *arg);
static int cisco_send(sc_p sc, int type, long par1, long par2);
+/* Parse type for struct ng_cisco_ipaddr */
+static const struct ng_parse_struct_info
+ ng_cisco_ipaddr_type_info = NG_CISCO_IPADDR_TYPE_INFO;
+static const struct ng_parse_type ng_cisco_ipaddr_type = {
+ &ng_parse_struct_type,
+ &ng_cisco_ipaddr_type_info
+};
+
+/* Parse type for struct ng_async_stat */
+static const struct ng_parse_struct_info
+ ng_cisco_stats_type_info = NG_CISCO_STATS_TYPE_INFO;
+static const struct ng_parse_type ng_cisco_stats_type = {
+ &ng_parse_struct_type,
+ &ng_cisco_stats_type_info,
+};
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_cisco_cmdlist[] = {
+ {
+ NGM_CISCO_COOKIE,
+ NGM_CISCO_SET_IPADDR,
+ "setipaddr",
+ &ng_cisco_ipaddr_type,
+ NULL
+ },
+ {
+ NGM_CISCO_COOKIE,
+ NGM_CISCO_GET_IPADDR,
+ "getipaddr",
+ NULL,
+ &ng_cisco_ipaddr_type
+ },
+ {
+ NGM_CISCO_COOKIE,
+ NGM_CISCO_GET_STATUS,
+ "getstats",
+ NULL,
+ &ng_cisco_stats_type
+ },
+ { 0 }
+};
+
/* Node type */
static struct ng_type typestruct = {
NG_VERSION,
@@ -144,7 +187,8 @@ static struct ng_type typestruct = {
NULL,
cisco_rcvdata,
cisco_rcvdata,
- cisco_disconnect
+ cisco_disconnect,
+ ng_cisco_cmdlist
};
NETGRAPH_INIT(cisco, &typestruct);
@@ -237,7 +281,7 @@ cisco_rcvmsg(node_p node, struct ng_mesg *msg,
pos = sprintf(arg,
"keepalive period: %d sec; ", KEEPALIVE_SECS);
pos += sprintf(arg + pos,
- "unacknowledged keepalives: %ld", sc->seq_retries);
+ "unacknowledged keepalives: %ld", sc->seqRetries);
resp->header.arglen = pos + 1;
break;
}
@@ -278,16 +322,16 @@ cisco_rcvmsg(node_p node, struct ng_mesg *msg,
}
case NGM_CISCO_GET_STATUS:
{
- struct ngciscostat *stat;
+ struct ng_cisco_stats *stat;
NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT);
if (!resp) {
error = ENOMEM;
break;
}
- stat = (struct ngciscostat *) resp->data;
- stat->seq_retries = sc->seq_retries;
- stat->keepalive_period = KEEPALIVE_SECS;
+ stat = (struct ng_cisco_stats *)resp->data;
+ stat->seqRetries = sc->seqRetries;
+ stat->keepAlivePeriod = KEEPALIVE_SECS;
break;
}
default:
@@ -445,7 +489,7 @@ cisco_input(sc_p sc, struct mbuf *m, meta_p meta)
sc->remote_seq = ntohl(p->par1);
if (sc->local_seq == ntohl(p->par2)) {
sc->local_seq++;
- sc->seq_retries = 0;
+ sc->seqRetries = 0;
}
break;
case CISCO_ADDR_REQ:
@@ -508,7 +552,7 @@ cisco_keepalive(void *arg)
int s = splimp();
cisco_send(sc, CISCO_KEEPALIVE_REQ, sc->local_seq, sc->remote_seq);
- sc->seq_retries++;
+ sc->seqRetries++;
splx(s);
sc->handle = timeout(cisco_keepalive, sc, hz * KEEPALIVE_SECS);
}
diff --git a/sys/netgraph/ng_cisco.h b/sys/netgraph/ng_cisco.h
index 559cc14..a51dbfa 100644
--- a/sys/netgraph/ng_cisco.h
+++ b/sys/netgraph/ng_cisco.h
@@ -56,21 +56,38 @@
/* Netgraph commands */
enum {
- /* This takes two struct in_addr's: the IP address and netmask */
- NGM_CISCO_SET_IPADDR = 1,
-
- /* This is both received and *sent* by this node (to the "inet"
- peer). The reply contains the same info as NGM_CISCO_SET_IPADDR. */
- NGM_CISCO_GET_IPADDR,
+ NGM_CISCO_SET_IPADDR = 1, /* requires a struct ng_cisco_ipaddr */
+ NGM_CISCO_GET_IPADDR, /* returns a struct ng_cisco_ipaddr */
+ NGM_CISCO_GET_STATUS, /* returns a struct ng_cisco_stat */
+};
- /* This returns a struct ngciscostat (see below) */
- NGM_CISCO_GET_STATUS,
+struct ng_cisco_ipaddr {
+ struct in_addr ipaddr; /* IP address */
+ struct in_addr netmask; /* Netmask */
};
-struct ngciscostat {
- u_int32_t seq_retries; /* # unack'd retries */
- u_int32_t keepalive_period; /* in seconds */
+/* Keep this in sync with the above structure definition */
+#define NG_CISCO_IPADDR_TYPE_INFO { \
+ { \
+ { "ipaddr", &ng_parse_ipaddr_type }, \
+ { "netmask", &ng_parse_ipaddr_type }, \
+ { NULL }, \
+ } \
+}
+
+struct ng_cisco_stats {
+ u_int32_t seqRetries; /* # unack'd retries */
+ u_int32_t keepAlivePeriod; /* in seconds */
};
+/* Keep this in sync with the above structure definition */
+#define NG_CISCO_STATS_TYPE_INFO { \
+ { \
+ { "seqRetries", &ng_parse_int32_type }, \
+ { "keepAlivePeriod", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
#endif /* _NETGRAPH_CISCO_H_ */
diff --git a/sys/netgraph/ng_echo.c b/sys/netgraph/ng_echo.c
index a834659..e5c35b5 100644
--- a/sys/netgraph/ng_echo.c
+++ b/sys/netgraph/ng_echo.c
@@ -75,7 +75,8 @@ static struct ng_type typestruct = {
NULL,
nge_rcvdata,
nge_rcvdata,
- nge_disconnect
+ nge_disconnect,
+ NULL
};
NETGRAPH_INIT(echo, &typestruct);
diff --git a/sys/netgraph/ng_ether.h b/sys/netgraph/ng_ether.h
index 45625e4..f492361 100644
--- a/sys/netgraph/ng_ether.h
+++ b/sys/netgraph/ng_ether.h
@@ -45,11 +45,19 @@
/* Node type name and magic cookie */
#define NG_ETHER_NODE_TYPE "ether"
-#define NGM_ETHER_COOKIE 917786904
+#define NGM_ETHER_COOKIE 917786904
/* Hook names */
#define NG_ETHER_HOOK_ORPHAN "orphans"
#define NG_ETHER_HOOK_DIVERT "divert"
+/* For adding/removing Ethernet multicast addresses */
+enum {
+ NGM_ETHER_ADD_MULTICAST = 1, /* supply struct ether_addr */
+ NGM_ETHER_DEL_MULTICAST, /* supply struct ether_addr */
+ NGM_ETHER_GET_MULTICAST, /* returns array of struct ether_addr */
+ NGM_ETHER_CLR_MULTICAST, /* clears all multicast addresses */
+};
+
#endif /* _NETGRAPH_NG_ETHER_H_ */
diff --git a/sys/netgraph/ng_frame_relay.c b/sys/netgraph/ng_frame_relay.c
index 7923ad2..92437e9 100644
--- a/sys/netgraph/ng_frame_relay.c
+++ b/sys/netgraph/ng_frame_relay.c
@@ -151,7 +151,8 @@ static struct ng_type typestruct = {
NULL,
ngfrm_rcvdata,
ngfrm_rcvdata,
- ngfrm_disconnect
+ ngfrm_disconnect,
+ NULL
};
NETGRAPH_INIT(framerelay, &typestruct);
@@ -246,7 +247,7 @@ ngfrm_constructor(node_p *nodep)
static int
ngfrm_newhook(node_p node, hook_p hook, const char *name)
{
- const sc_p sc = node->private;
+ const sc_p sc = node->private;
const char *cp;
char *eptr;
int dlci = 0;
diff --git a/sys/netgraph/ng_hole.c b/sys/netgraph/ng_hole.c
index 6b3768c..c0b5dcc 100644
--- a/sys/netgraph/ng_hole.c
+++ b/sys/netgraph/ng_hole.c
@@ -71,7 +71,8 @@ static struct ng_type typestruct = {
NULL,
ngh_rcvdata,
ngh_rcvdata,
- ngh_disconnect
+ ngh_disconnect,
+ NULL
};
NETGRAPH_INIT(hole, &typestruct);
diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c
index 6a6cbdf3..d450d2e 100644
--- a/sys/netgraph/ng_iface.c
+++ b/sys/netgraph/ng_iface.c
@@ -73,13 +73,14 @@
#include <net/if_types.h>
#include <net/netisr.h>
+#include <netinet/in.h>
+
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_iface.h>
#include <netgraph/ng_cisco.h>
#ifdef INET
-#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
@@ -206,7 +207,8 @@ static struct ng_type typestruct = {
NULL,
ng_iface_rcvdata,
ng_iface_rcvdata,
- ng_iface_disconnect
+ ng_iface_disconnect,
+ NULL
};
NETGRAPH_INIT(iface, &typestruct);
@@ -683,12 +685,8 @@ ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
int s, error = 0;
/* Sanity checks */
-#ifdef DIAGNOSTIC
- if (iffam == NULL)
- panic(__FUNCTION__);
- if ((m->m_flags & M_PKTHDR) == 0)
- panic(__FUNCTION__);
-#endif
+ KASSERT(iffam != NULL, ("%s: iffam", __FUNCTION__));
+ KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__));
if (m == NULL)
return (EINVAL);
if ((ifp->if_flags & IFF_UP) == 0) {
diff --git a/sys/netgraph/ng_ksocket.c b/sys/netgraph/ng_ksocket.c
index 485eeb5..2ce2b4e 100644
--- a/sys/netgraph/ng_ksocket.c
+++ b/sys/netgraph/ng_ksocket.c
@@ -52,20 +52,26 @@
#include <sys/mbuf.h>
#include <sys/proc.h>
#include <sys/malloc.h>
+#include <sys/ctype.h>
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syslog.h>
#include <sys/uio.h>
+#include <sys/un.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
#include <netgraph/ng_ksocket.h>
#include <netinet/in.h>
#include <netatalk/at.h>
+#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
+#define SADATA_OFFSET (OFFSETOF(struct sockaddr, sa_data))
+
/* Node private data */
struct ng_ksocket_private {
hook_p hook;
@@ -88,28 +94,6 @@ struct ng_ksocket_alias {
const int family;
};
-/* Helper functions */
-static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
-static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
- const char *s, int family);
-
-/* Node type descriptor */
-static struct ng_type ng_ksocket_typestruct = {
- NG_VERSION,
- NG_KSOCKET_NODE_TYPE,
- NULL,
- ng_ksocket_constructor,
- ng_ksocket_rcvmsg,
- ng_ksocket_rmnode,
- ng_ksocket_newhook,
- NULL,
- NULL,
- ng_ksocket_rcvdata,
- ng_ksocket_rcvdata,
- ng_ksocket_disconnect
-};
-NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
-
/* Protocol family aliases */
static const struct ng_ksocket_alias ng_ksocket_families[] = {
{ "local", PF_LOCAL },
@@ -150,6 +134,350 @@ static const struct ng_ksocket_alias ng_ksocket_protos[] = {
{ NULL, -1 },
};
+/* Helper functions */
+static void ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
+static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
+ const char *s, int family);
+
+/************************************************************************
+ STRUCT SOCKADDR PARSE TYPE
+ ************************************************************************/
+
+/* Get the length of the data portion of a generic struct sockaddr */
+static int
+ng_parse_generic_sockdata_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ const struct sockaddr *sa;
+
+ sa = (const struct sockaddr *)(buf - SADATA_OFFSET);
+ return sa->sa_len - SADATA_OFFSET;
+}
+
+/* Type for the variable length data portion of a generic struct sockaddr */
+static const struct ng_parse_type ng_ksocket_generic_sockdata_type = {
+ &ng_parse_bytearray_type,
+ &ng_parse_generic_sockdata_getLength
+};
+
+/* Type for a generic struct sockaddr */
+static const struct ng_parse_struct_info ng_parse_generic_sockaddr_type_info = {
+ {
+ { "len", &ng_parse_int8_type },
+ { "family", &ng_parse_int8_type },
+ { "data", &ng_ksocket_generic_sockdata_type },
+ { NULL }
+ }
+};
+static const struct ng_parse_type ng_ksocket_generic_sockaddr_type = {
+ &ng_parse_struct_type,
+ &ng_parse_generic_sockaddr_type_info
+};
+
+/* Convert a struct sockaddr from ASCII to binary. If its a protocol
+ family that we specially handle, do that, otherwise defer to the
+ generic parse type ng_ksocket_generic_sockaddr_type. */
+static int
+ng_ksocket_sockaddr_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ struct sockaddr *const sa = (struct sockaddr *)buf;
+ enum ng_parse_token tok;
+ char fambuf[32];
+ int family, len;
+ char *t;
+
+ /* If next token is a left curly brace, use generic parse type */
+ if ((tok = ng_parse_get_token(s, off, &len)) == T_LBRACE) {
+ return (*ng_ksocket_generic_sockaddr_type.supertype->parse)
+ (&ng_ksocket_generic_sockaddr_type,
+ s, off, start, buf, buflen);
+ }
+
+ /* Get socket address family followed by a slash */
+ while (isspace(s[*off]))
+ (*off)++;
+ if ((t = index(s + *off, '/')) == NULL)
+ return (EINVAL);
+ if ((len = t - (s + *off)) > sizeof(fambuf) - 1)
+ return (EINVAL);
+ strncpy(fambuf, s + *off, len);
+ fambuf[len] = '\0';
+ *off += len + 1;
+ if ((family = ng_ksocket_parse(ng_ksocket_families, fambuf, 0)) == -1)
+ return (EINVAL);
+
+ /* Set family */
+ if (*buflen < SADATA_OFFSET)
+ return (ERANGE);
+ sa->sa_family = family;
+
+ /* Set family-specific data and length */
+ switch (sa->sa_family) {
+ case PF_LOCAL: /* Get pathname */
+ {
+ const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
+ struct sockaddr_un *const sun = (struct sockaddr_un *)sa;
+ int toklen, pathlen;
+ char *path;
+
+ if ((path = ng_get_string_token(s, off, &toklen)) == NULL)
+ return (EINVAL);
+ pathlen = strlen(path);
+ if (pathlen > SOCK_MAXADDRLEN) {
+ FREE(path, M_NETGRAPH);
+ return (E2BIG);
+ }
+ if (*buflen < pathoff + pathlen) {
+ FREE(path, M_NETGRAPH);
+ return (ERANGE);
+ }
+ *off += toklen;
+ bcopy(path, sun->sun_path, pathlen);
+ sun->sun_len = pathoff + pathlen;
+ FREE(path, M_NETGRAPH);
+ break;
+ }
+
+ case PF_INET: /* Get an IP address with optional port */
+ {
+ struct sockaddr_in *const sin = (struct sockaddr_in *)sa;
+ int i;
+
+ /* Parse this: <ipaddress>[:port] */
+ for (i = 0; i < 4; i++) {
+ u_long val;
+ char *eptr;
+
+ val = strtoul(s + *off, &eptr, 10);
+ if (val > 0xff || eptr == s + *off)
+ return (EINVAL);
+ *off += (eptr - (s + *off));
+ ((u_char *)&sin->sin_addr)[i] = (u_char)val;
+ if (i < 3) {
+ if (s[*off] != '.')
+ return (EINVAL);
+ (*off)++;
+ } else if (s[*off] == ':') {
+ (*off)++;
+ val = strtoul(s + *off, &eptr, 10);
+ if (val > 0xffff || eptr == s + *off)
+ return (EINVAL);
+ *off += (eptr - (s + *off));
+ sin->sin_port = htons(val);
+ } else
+ sin->sin_port = 0;
+ }
+ bzero(&sin->sin_zero, sizeof(sin->sin_zero));
+ sin->sin_len = sizeof(*sin);
+ break;
+ }
+
+#if 0
+ case PF_APPLETALK: /* XXX implement these someday */
+ case PF_INET6:
+ case PF_IPX:
+#endif
+
+ default:
+ return (EINVAL);
+ }
+
+ /* Done */
+ *buflen = sa->sa_len;
+ return (0);
+}
+
+/* Convert a struct sockaddr from binary to ASCII */
+static int
+ng_ksocket_sockaddr_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ const struct sockaddr *sa = (const struct sockaddr *)(data + *off);
+ int slen = 0;
+
+ /* Output socket address, either in special or generic format */
+ switch (sa->sa_family) {
+ case PF_LOCAL:
+ {
+ const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);
+ const struct sockaddr_un *sun = (const struct sockaddr_un *)sa;
+ const int pathlen = sun->sun_len - pathoff;
+ char pathbuf[SOCK_MAXADDRLEN + 1];
+ char *pathtoken;
+
+ bcopy(sun->sun_path, pathbuf, pathlen);
+ pathbuf[pathlen] = '\0';
+ if ((pathtoken = ng_encode_string(pathbuf)) == NULL)
+ return (ENOMEM);
+ slen += snprintf(cbuf, cbuflen, "local/%s", pathtoken);
+ FREE(pathtoken, M_NETGRAPH);
+ if (slen >= cbuflen)
+ return (ERANGE);
+ *off += sun->sun_len;
+ return (0);
+ }
+
+ case PF_INET:
+ {
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+
+ slen += snprintf(cbuf, cbuflen, "inet/%d.%d.%d.%d",
+ ((const u_char *)&sin->sin_addr)[0],
+ ((const u_char *)&sin->sin_addr)[1],
+ ((const u_char *)&sin->sin_addr)[2],
+ ((const u_char *)&sin->sin_addr)[3]);
+ if (sin->sin_port != 0) {
+ slen += snprintf(cbuf + strlen(cbuf),
+ cbuflen - strlen(cbuf), ":%d",
+ (u_int)ntohs(sin->sin_port));
+ }
+ if (slen >= cbuflen)
+ return (ERANGE);
+ *off += sizeof(*sin);
+ return(0);
+ }
+
+#if 0
+ case PF_APPLETALK: /* XXX implement these someday */
+ case PF_INET6:
+ case PF_IPX:
+#endif
+
+ default:
+ return (*ng_ksocket_generic_sockaddr_type.supertype->unparse)
+ (&ng_ksocket_generic_sockaddr_type,
+ data, off, cbuf, cbuflen);
+ }
+}
+
+/* Parse type for struct sockaddr */
+static const struct ng_parse_type ng_ksocket_sockaddr_type = {
+ NULL,
+ NULL,
+ NULL,
+ &ng_ksocket_sockaddr_parse,
+ &ng_ksocket_sockaddr_unparse,
+ NULL /* no such thing as a default struct sockaddr */
+};
+
+/************************************************************************
+ STRUCT NG_KSOCKET_SOCKOPT PARSE TYPE
+ ************************************************************************/
+
+/* Get length of the struct ng_ksocket_sockopt value field, which is the
+ just the excess of the message argument portion over the length of
+ the struct ng_ksocket_sockopt. */
+static int
+ng_parse_sockoptval_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ static const int offset = OFFSETOF(struct ng_ksocket_sockopt, value);
+ const struct ng_ksocket_sockopt *sopt;
+ const struct ng_mesg *msg;
+
+ sopt = (const struct ng_ksocket_sockopt *)(buf - offset);
+ msg = (const struct ng_mesg *)((const u_char *)sopt - sizeof(*msg));
+ return msg->header.arglen - sizeof(*sopt);
+}
+
+/* Parse type for the option value part of a struct ng_ksocket_sockopt
+ XXX Eventually, we should handle the different socket options specially.
+ XXX This would avoid byte order problems, eg an integer value of 1 is
+ XXX going to be "[1]" for little endian or "[3=1]" for big endian. */
+static const struct ng_parse_type ng_ksocket_sockoptval_type = {
+ &ng_parse_bytearray_type,
+ &ng_parse_sockoptval_getLength
+};
+
+/* Parse type for struct ng_ksocket_sockopt */
+static const struct ng_parse_struct_info ng_ksocket_sockopt_type_info
+ = NG_KSOCKET_SOCKOPT_INFO(&ng_ksocket_sockoptval_type);
+static const struct ng_parse_type ng_ksocket_sockopt_type = {
+ &ng_parse_struct_type,
+ &ng_ksocket_sockopt_type_info,
+};
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_ksocket_cmds[] = {
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_BIND,
+ "bind",
+ &ng_ksocket_sockaddr_type,
+ NULL
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_LISTEN,
+ "listen",
+ &ng_parse_int32_type,
+ NULL
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_ACCEPT,
+ "accept",
+ NULL,
+ &ng_ksocket_sockaddr_type
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_CONNECT,
+ "connect",
+ &ng_ksocket_sockaddr_type,
+ NULL
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_GETNAME,
+ "getname",
+ NULL,
+ &ng_ksocket_sockaddr_type
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_GETPEERNAME,
+ "getpeername",
+ NULL,
+ &ng_ksocket_sockaddr_type
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_SETOPT,
+ "setopt",
+ &ng_ksocket_sockopt_type,
+ NULL
+ },
+ {
+ NGM_KSOCKET_COOKIE,
+ NGM_KSOCKET_GETOPT,
+ "getopt",
+ &ng_ksocket_sockopt_type,
+ &ng_ksocket_sockopt_type
+ },
+ { 0 }
+};
+
+/* Node type descriptor */
+static struct ng_type ng_ksocket_typestruct = {
+ NG_VERSION,
+ NG_KSOCKET_NODE_TYPE,
+ NULL,
+ ng_ksocket_constructor,
+ ng_ksocket_rcvmsg,
+ ng_ksocket_rmnode,
+ ng_ksocket_newhook,
+ NULL,
+ NULL,
+ ng_ksocket_rcvdata,
+ ng_ksocket_rcvdata,
+ ng_ksocket_disconnect,
+ ng_ksocket_cmds
+};
+NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct);
+
#define ERROUT(x) do { error = (x); goto done; } while (0)
/************************************************************************
@@ -193,10 +521,10 @@ ng_ksocket_constructor(node_p *nodep)
static int
ng_ksocket_newhook(node_p node, hook_p hook, const char *name0)
{
+ struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
const priv_p priv = node->private;
char *s1, *s2, name[NG_HOOKLEN+1];
int family, type, protocol, error;
- struct proc *p = &proc0; /* XXX help what to do here */
/* Check if we're already connected */
if (priv->hook != NULL)
@@ -243,9 +571,10 @@ static int
ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
const char *raddr, struct ng_mesg **rptr)
{
+ struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
const priv_p priv = node->private;
+ struct socket *const so = priv->so;
struct ng_mesg *resp = NULL;
- struct proc *p = &proc0;
int error = 0;
switch (msg->header.typecookie) {
@@ -253,62 +582,68 @@ ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
switch (msg->header.cmd) {
case NGM_KSOCKET_BIND:
{
- struct sockaddr *sa = (struct sockaddr *)msg->data;
- struct socket *const so = priv->so;
+ struct sockaddr *const sa
+ = (struct sockaddr *)msg->data;
- /* Must have a connected hook first */
- if (priv->hook == NULL)
- ERROUT(ENETDOWN);
+ /* Sanity check */
+ if (msg->header.arglen < SADATA_OFFSET
+ || msg->header.arglen < sa->sa_len)
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
- /* Set and sanity check sockaddr length */
- if (msg->header.arglen > SOCK_MAXADDRLEN)
- ERROUT(ENAMETOOLONG);
- sa->sa_len = msg->header.arglen;
+ /* Bind */
error = sobind(so, sa, p);
break;
}
case NGM_KSOCKET_LISTEN:
{
- struct socket *const so = priv->so;
- int backlog;
-
- /* Must have a connected hook first */
- if (priv->hook == NULL)
- ERROUT(ENETDOWN);
-
- /* Get backlog argument */
+ /* Sanity check */
if (msg->header.arglen != sizeof(int))
ERROUT(EINVAL);
- backlog = *((int *)msg->data);
+ if (so == NULL)
+ ERROUT(ENXIO);
- /* Do listen */
- if ((error = solisten(so, backlog, p)) != 0)
+ /* Listen */
+ if ((error = solisten(so, *((int *)msg->data), p)) != 0)
break;
/* Notify sender when we get a connection attempt */
/* XXX implement me */
+ error = ENODEV;
break;
}
case NGM_KSOCKET_ACCEPT:
{
- ERROUT(ENODEV); /* XXX implement me */
+ /* Sanity check */
+ if (msg->header.arglen != 0)
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
+
+ /* Accept on the socket in a non-blocking way */
+ /* Create a new ksocket node for the new connection */
+ /* Return a response with the peer's sockaddr and
+ the absolute name of the newly created node */
+
+ /* XXX implement me */
+
+ error = ENODEV;
break;
}
case NGM_KSOCKET_CONNECT:
{
- struct socket *const so = priv->so;
- struct sockaddr *sa = (struct sockaddr *)msg->data;
-
- /* Must have a connected hook first */
- if (priv->hook == NULL)
- ERROUT(ENETDOWN);
+ struct sockaddr *const sa
+ = (struct sockaddr *)msg->data;
- /* Set and sanity check sockaddr length */
- if (msg->header.arglen > SOCK_MAXADDRLEN)
- ERROUT(ENAMETOOLONG);
- sa->sa_len = msg->header.arglen;
+ /* Sanity check */
+ if (msg->header.arglen < SADATA_OFFSET
+ || msg->header.arglen < sa->sa_len)
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
/* Do connect */
if ((so->so_state & SS_ISCONNECTING) != 0)
@@ -325,26 +660,105 @@ ng_ksocket_rcvmsg(node_p node, struct ng_mesg *msg,
}
case NGM_KSOCKET_GETNAME:
- {
- ERROUT(ENODEV); /* XXX implement me */
- break;
- }
-
case NGM_KSOCKET_GETPEERNAME:
{
- ERROUT(ENODEV); /* XXX implement me */
+ int (*func)(struct socket *so, struct sockaddr **nam);
+ struct sockaddr *sa = NULL;
+ int len;
+
+ /* Sanity check */
+ if (msg->header.arglen != 0)
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
+
+ /* Get function */
+ if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) {
+ if ((so->so_state
+ & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
+ ERROUT(ENOTCONN);
+ func = so->so_proto->pr_usrreqs->pru_peeraddr;
+ } else
+ func = so->so_proto->pr_usrreqs->pru_sockaddr;
+
+ /* Get local or peer address */
+ if ((error = (*func)(so, &sa)) != 0)
+ goto bail;
+ len = (sa == NULL) ? 0 : sa->sa_len;
+
+ /* Send it back in a response */
+ NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ goto bail;
+ }
+ bcopy(sa, resp->data, len);
+
+ bail:
+ /* Cleanup */
+ if (sa != NULL)
+ FREE(sa, M_SONAME);
break;
}
case NGM_KSOCKET_GETOPT:
{
- ERROUT(ENODEV); /* XXX implement me */
+ struct ng_ksocket_sockopt *ksopt =
+ (struct ng_ksocket_sockopt *)msg->data;
+ struct sockopt sopt;
+
+ /* Sanity check */
+ if (msg->header.arglen != sizeof(*ksopt))
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
+
+ /* Get response with room for option value */
+ NG_MKRESPONSE(resp, msg, sizeof(*ksopt)
+ + NG_KSOCKET_MAX_OPTLEN, M_NOWAIT);
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+
+ /* Get socket option, and put value in the response */
+ sopt.sopt_dir = SOPT_GET;
+ sopt.sopt_level = ksopt->level;
+ sopt.sopt_name = ksopt->name;
+ sopt.sopt_p = p;
+ sopt.sopt_valsize = NG_KSOCKET_MAX_OPTLEN;
+ ksopt = (struct ng_ksocket_sockopt *)resp->data;
+ sopt.sopt_val = ksopt->value;
+ if ((error = sogetopt(so, &sopt)) != 0) {
+ FREE(resp, M_NETGRAPH);
+ break;
+ }
+
+ /* Set actual value length */
+ resp->header.arglen = sizeof(*ksopt)
+ + sopt.sopt_valsize;
break;
}
case NGM_KSOCKET_SETOPT:
{
- ERROUT(ENODEV); /* XXX implement me */
+ struct ng_ksocket_sockopt *const ksopt =
+ (struct ng_ksocket_sockopt *)msg->data;
+ const int valsize = msg->header.arglen - sizeof(*ksopt);
+ struct sockopt sopt;
+
+ /* Sanity check */
+ if (valsize < 0)
+ ERROUT(EINVAL);
+ if (so == NULL)
+ ERROUT(ENXIO);
+
+ /* Set socket option */
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_level = ksopt->level;
+ sopt.sopt_name = ksopt->name;
+ sopt.sopt_val = ksopt->value;
+ sopt.sopt_valsize = valsize;
+ sopt.sopt_p = p;
+ error = sosetopt(so, &sopt);
break;
}
@@ -373,10 +787,10 @@ done:
static int
ng_ksocket_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
{
+ struct proc *p = curproc ? curproc : &proc0; /* XXX broken */
const node_p node = hook->node;
const priv_p priv = node->private;
struct socket *const so = priv->so;
- struct proc *p = &proc0;
int error;
NG_FREE_META(meta);
@@ -394,6 +808,9 @@ ng_ksocket_rmnode(node_p node)
/* Close our socket (if any) */
if (priv->so != NULL) {
+
+ priv->so->so_upcall = NULL;
+ priv->so->so_rcv.sb_flags &= ~SB_UPCALL;
soclose(priv->so);
priv->so = NULL;
}
@@ -455,8 +872,16 @@ ng_ksocket_incoming(struct socket *so, void *arg, int waitflag)
flags = MSG_DONTWAIT;
do {
if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive)
- (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0)
+ (so, &nam, &auio, &m, (struct mbuf **)0, &flags)) == 0
+ && m != NULL) {
+ struct mbuf *n;
+
+ /* Don't trust the various socket layers to get the
+ packet header and length correct (eg. kern/15175) */
+ for (n = m, m->m_pkthdr.len = 0; n; n = n->m_next)
+ m->m_pkthdr.len += n->m_len;
NG_SEND_DATA(error, priv->hook, m, meta);
+ }
} while (error == 0 && m != NULL);
splx(s);
}
@@ -480,7 +905,7 @@ ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
/* Try parsing as a number */
val = (int)strtoul(s, &eptr, 10);
- if (val <= 0 || *eptr != '\0')
+ if (val < 0 || *eptr != '\0')
return (-1);
return (val);
}
diff --git a/sys/netgraph/ng_ksocket.h b/sys/netgraph/ng_ksocket.h
index 93f3752..48cb41f 100644
--- a/sys/netgraph/ng_ksocket.h
+++ b/sys/netgraph/ng_ksocket.h
@@ -47,6 +47,28 @@
#define NG_KSOCKET_NODE_TYPE "ksocket"
#define NGM_KSOCKET_COOKIE 942710669
+/* For NGM_KSOCKET_SETOPT and NGM_KSOCKET_GETOPT control messages */
+struct ng_ksocket_sockopt {
+ u_int32_t level; /* second arg of [gs]etsockopt() */
+ u_int32_t name; /* third arg of [gs]etsockopt() */
+ u_char value[0]; /* fourth arg of [gs]etsockopt() */
+};
+
+/* Max length socket option we can return via NGM_KSOCKET_GETOPT
+ XXX This should not be necessary, we should dynamically size
+ XXX the response. Until then.. */
+#define NG_KSOCKET_MAX_OPTLEN 1024
+
+/* Keep this in sync with the above structure definition */
+#define NG_KSOCKET_SOCKOPT_INFO(svtype) { \
+ { \
+ { "level", &ng_parse_int32_type }, \
+ { "name", &ng_parse_int32_type }, \
+ { "value", (svtype) }, \
+ { NULL }, \
+ } \
+}
+
/* Netgraph commands */
enum {
NGM_KSOCKET_BIND = 1,
diff --git a/sys/netgraph/ng_lmi.c b/sys/netgraph/ng_lmi.c
index 9dcfa38..3a3afc9 100644
--- a/sys/netgraph/ng_lmi.c
+++ b/sys/netgraph/ng_lmi.c
@@ -109,7 +109,8 @@ static struct ng_type typestruct = {
NULL,
nglmi_rcvdata,
nglmi_rcvdata,
- nglmi_disconnect
+ nglmi_disconnect,
+ NULL
};
NETGRAPH_INIT(lmi, &typestruct);
diff --git a/sys/netgraph/ng_message.h b/sys/netgraph/ng_message.h
index 66c7fba..aab7314 100644
--- a/sys/netgraph/ng_message.h
+++ b/sys/netgraph/ng_message.h
@@ -65,10 +65,33 @@ struct ng_mesg {
} header;
char data[0]; /* placeholder for actual data */
};
-#define NG_VERSION 1
+
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_NG_MESG_INFO(dtype) { \
+ { \
+ { "version", &ng_parse_int8_type }, \
+ { "spare", &ng_parse_int8_type }, \
+ { "arglen", &ng_parse_int16_type }, \
+ { "flags", &ng_parse_int32_type }, \
+ { "token", &ng_parse_int32_type }, \
+ { "typecookie", &ng_parse_int32_type }, \
+ { "cmd", &ng_parse_int32_type }, \
+ { "cmdstr", &ng_parse_cmdbuf_type }, \
+ { "data", (dtype) }, \
+ { NULL }, \
+ } \
+}
+
+/* Negraph type binary compatibility field */
+#define NG_VERSION 2
+
+/* Flags field flags */
#define NGF_ORIG 0x0000 /* the msg is the original request */
#define NGF_RESP 0x0001 /* the message is a response */
+/* Type of a unique node ID */
+#define ng_ID_t unsigned int
+
/*
* Here we describe the "generic" messages that all nodes inherently
* understand. With the exception of NGM_TEXT_STATUS, these are handled
@@ -76,46 +99,84 @@ struct ng_mesg {
*/
/* Generic message type cookie */
-#define NGM_GENERIC_COOKIE 851672668
+#define NGM_GENERIC_COOKIE 851672668
/* Generic messages defined for this type cookie */
-#define NGM_SHUTDOWN 0x0001 /* no args */
-#define NGM_MKPEER 0x0002
-#define NGM_CONNECT 0x0003
-#define NGM_NAME 0x0004
-#define NGM_RMHOOK 0x0005
-#define NGM_NODEINFO 0x0006 /* get nodeinfo for the target */
-#define NGM_LISTHOOKS 0x0007 /* get nodeinfo for the target + hook info */
-#define NGM_LISTNAMES 0x0008 /* list all globally named nodes */
-#define NGM_LISTNODES 0x0009 /* list all nodes, named and unnamed */
-#define NGM_LISTTYPES 0x000a /* list all installed node types */
-#define NGM_TEXT_STATUS 0x000b /* (optional) returns human readable status */
+#define NGM_SHUTDOWN 1 /* shut down node */
+#define NGM_MKPEER 2 /* create and attach a peer node */
+#define NGM_CONNECT 3 /* connect two nodes */
+#define NGM_NAME 4 /* give a node a name */
+#define NGM_RMHOOK 5 /* break a connection btw. two nodes */
+#define NGM_NODEINFO 6 /* get nodeinfo for the target */
+#define NGM_LISTHOOKS 7 /* get list of hooks on node */
+#define NGM_LISTNAMES 8 /* list all globally named nodes */
+#define NGM_LISTNODES 9 /* list all nodes, named and unnamed */
+#define NGM_LISTTYPES 10 /* list all installed node types */
+#define NGM_TEXT_STATUS 11 /* (optional) get text status report */
+#define NGM_BINARY2ASCII 12 /* convert struct ng_mesg to ascii */
+#define NGM_ASCII2BINARY 13 /* convert ascii to struct ng_mesg */
-/*
- * Args sections for generic NG commands. All strings are NUL-terminated.
- */
+/* Structure used for NGM_MKPEER */
struct ngm_mkpeer {
char type[NG_TYPELEN + 1]; /* peer type */
char ourhook[NG_HOOKLEN + 1]; /* hook name */
char peerhook[NG_HOOKLEN + 1]; /* peer hook name */
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_MKPEER_INFO() { \
+ { \
+ { "type", &ng_parse_typebuf_type }, \
+ { "ourhook", &ng_parse_hookbuf_type }, \
+ { "peerhook", &ng_parse_hookbuf_type }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_CONNECT */
struct ngm_connect {
char path[NG_PATHLEN + 1]; /* peer path */
char ourhook[NG_HOOKLEN + 1]; /* hook name */
char peerhook[NG_HOOKLEN + 1]; /* peer hook name */
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_CONNECT_INFO() { \
+ { \
+ { "path", &ng_parse_pathbuf_type }, \
+ { "ourhook", &ng_parse_hookbuf_type }, \
+ { "peerhook", &ng_parse_hookbuf_type }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_NAME */
struct ngm_name {
char name[NG_NODELEN + 1]; /* node name */
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_NAME_INFO() { \
+ { \
+ { "name", &ng_parse_nodebuf_type }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_RMHOOK */
struct ngm_rmhook {
char ourhook[NG_HOOKLEN + 1]; /* hook name */
};
-#define ng_ID_t unsigned int
-/* Structures used in response to NGM_NODEINFO and NGM_LISTHOOKS */
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_RMHOOK_INFO() { \
+ { \
+ { "hook", &ng_parse_hookbuf_type }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_NODEINFO */
struct nodeinfo {
char name[NG_NODELEN + 1]; /* node name (if any) */
char type[NG_TYPELEN + 1]; /* peer type */
@@ -123,34 +184,92 @@ struct nodeinfo {
u_int32_t hooks; /* number of active hooks */
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_NODEINFO_INFO() { \
+ { \
+ { "name", &ng_parse_nodebuf_type }, \
+ { "type", &ng_parse_typebuf_type }, \
+ { "id", &ng_parse_int32_type }, \
+ { "hooks", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_LISTHOOKS */
struct linkinfo {
char ourhook[NG_HOOKLEN + 1]; /* hook name */
char peerhook[NG_HOOKLEN + 1]; /* peer hook */
struct nodeinfo nodeinfo;
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_LINKINFO_INFO(nitype) { \
+ { \
+ { "ourhook", &ng_parse_hookbuf_type }, \
+ { "peerhook", &ng_parse_hookbuf_type }, \
+ { "nodeinfo", (nitype) }, \
+ { NULL }, \
+ } \
+}
+
struct hooklist {
struct nodeinfo nodeinfo; /* node information */
struct linkinfo link[0]; /* info about each hook */
};
-/* Structure used for NGM_LISTNAMES/NGM_LISTNODES (not node specific) */
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_HOOKLIST_INFO(nitype,litype) { \
+ { \
+ { "nodeinfo", (nitype) }, \
+ { "linkinfo", (litype) }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_LISTNAMES/NGM_LISTNODES */
struct namelist {
u_int32_t numnames;
struct nodeinfo nodeinfo[0];
};
-/* Structures used for NGM_LISTTYPES (not node specific) */
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_LISTNODES_INFO(niarraytype) { \
+ { \
+ { "numnames", &ng_parse_int32_type }, \
+ { "nodeinfo", (niarraytype) }, \
+ { NULL }, \
+ } \
+}
+
+/* Structure used for NGM_LISTTYPES */
struct typeinfo {
char typename[NG_TYPELEN + 1]; /* name of type */
u_int32_t numnodes; /* number alive */
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_TYPEINFO_INFO() { \
+ { \
+ { "typename", &ng_parse_typebuf_type }, \
+ { "typeinfo", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
struct typelist {
u_int32_t numtypes;
struct typeinfo typeinfo[0];
};
+/* Keep this in sync with the above structure definition */
+#define NG_GENERIC_TYPELIST_INFO(tiarraytype) { \
+ { \
+ { "numtypes", &ng_parse_int32_type }, \
+ { "typeinfo", (tiarraytype) }, \
+ { NULL }, \
+ } \
+}
+
/*
* For netgraph nodes that are somehow associated with file descriptors
* (e.g., a device that has a /dev entry and is also a netgraph node),
diff --git a/sys/netgraph/ng_parse.c b/sys/netgraph/ng_parse.c
new file mode 100644
index 0000000..795d1c1
--- /dev/null
+++ b/sys/netgraph/ng_parse.c
@@ -0,0 +1,1604 @@
+
+/*
+ * ng_parse.c
+ *
+ * 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 <archie@whistle.com>
+ *
+ * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ctype.h>
+
+#include <netinet/in.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+
+/* Compute alignment for primitive integral types */
+struct int16_temp {
+ char x;
+ int16_t y;
+};
+
+struct int32_temp {
+ char x;
+ int32_t y;
+};
+
+struct int64_temp {
+ char x;
+ int64_t y;
+};
+
+#define INT8_ALIGNMENT 1
+#define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y)
+#define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y)
+#define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y)
+
+/* Type of composite object: struct, array, or fixedarray */
+enum comptype {
+ CT_STRUCT,
+ CT_ARRAY,
+ CT_FIXEDARRAY,
+};
+
+/* Composite types helper functions */
+static int ng_parse_composite(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *start,
+ u_char *const buf, int *buflen, enum comptype ctype);
+static int ng_unparse_composite(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen,
+ enum comptype ctype);
+static int ng_get_composite_elem_default(const struct ng_parse_type *type,
+ int index, const u_char *start, u_char *buf,
+ int *buflen, enum comptype ctype);
+static int ng_get_composite_len(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf,
+ enum comptype ctype);
+static const struct ng_parse_type *ng_get_composite_etype(const struct
+ ng_parse_type *type, int index, enum comptype ctype);
+static int ng_parse_get_elem_pad(const struct ng_parse_type *type,
+ int index, enum comptype ctype, int posn);
+
+/* Parsing helper functions */
+static int ng_parse_skip_value(const char *s, int off, int *lenp);
+
+/* Poor man's virtual method calls */
+#define METHOD(t,m) (ng_get_ ## m ## _method(t))
+#define INVOKE(t,m) (*METHOD(t,m))
+
+static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t);
+static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t);
+static ng_getDefault_t *ng_get_getDefault_method(const
+ struct ng_parse_type *t);
+static ng_getAlign_t *ng_get_getAlign_method(const struct ng_parse_type *t);
+
+#define ALIGNMENT(t) (METHOD(t, getAlign) == NULL ? \
+ 0 : INVOKE(t, getAlign)(t))
+
+/* For converting binary to string */
+#define NG_PARSE_APPEND(fmt, args...) \
+ do { \
+ int len; \
+ \
+ len = snprintf((cbuf), (cbuflen), \
+ fmt , ## args); \
+ if (len >= (cbuflen)) \
+ return (ERANGE); \
+ (cbuf) += len; \
+ (cbuflen) -= len; \
+ } while (0)
+
+/************************************************************************
+ PUBLIC FUNCTIONS
+ ************************************************************************/
+
+/*
+ * Convert an ASCII string to binary according to the supplied type descriptor
+ */
+int
+ng_parse(const struct ng_parse_type *type,
+ const char *string, int *off, u_char *buf, int *buflen)
+{
+ return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
+}
+
+/*
+ * Convert binary to an ASCII string according to the supplied type descriptor
+ */
+int
+ng_unparse(const struct ng_parse_type *type,
+ const u_char *data, char *cbuf, int cbuflen)
+{
+ int off = 0;
+
+ return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
+}
+
+/*
+ * Fill in the default value according to the supplied type descriptor
+ */
+int
+ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
+{
+ ng_getDefault_t *const func = METHOD(type, getDefault);
+
+ if (func == NULL)
+ return (EOPNOTSUPP);
+ return (*func)(type, buf, buf, buflen);
+}
+
+
+/************************************************************************
+ STRUCTURE TYPE
+ ************************************************************************/
+
+static int
+ng_struct_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
+}
+
+static int
+ng_struct_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
+}
+
+static int
+ng_struct_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int off = 0;
+
+ return ng_parse_composite(type,
+ "{}", &off, start, buf, buflen, CT_STRUCT);
+}
+
+static int
+ng_struct_getAlign(const struct ng_parse_type *type)
+{
+ const struct ng_parse_struct_info *si = type->info;
+ const struct ng_parse_struct_field *field;
+ int align = 0;
+
+ for (field = si->fields; field->name != NULL; field++) {
+ int falign = ALIGNMENT(field->type);
+
+ if (falign > align)
+ align = falign;
+ }
+ return align;
+}
+
+const struct ng_parse_type ng_parse_struct_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_struct_parse,
+ ng_struct_unparse,
+ ng_struct_getDefault,
+ ng_struct_getAlign
+};
+
+/************************************************************************
+ FIXED LENGTH ARRAY TYPE
+ ************************************************************************/
+
+static int
+ng_fixedarray_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ return ng_parse_composite(type,
+ s, off, start, buf, buflen, CT_FIXEDARRAY);
+}
+
+static int
+ng_fixedarray_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ return ng_unparse_composite(type,
+ data, off, cbuf, cbuflen, CT_FIXEDARRAY);
+}
+
+static int
+ng_fixedarray_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int off = 0;
+
+ return ng_parse_composite(type,
+ "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
+}
+
+static int
+ng_fixedarray_getAlign(const struct ng_parse_type *type)
+{
+ const struct ng_parse_fixedarray_info *fi = type->info;
+
+ return ALIGNMENT(fi->elementType);
+}
+
+const struct ng_parse_type ng_parse_fixedarray_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_fixedarray_parse,
+ ng_fixedarray_unparse,
+ ng_fixedarray_getDefault,
+ ng_fixedarray_getAlign
+};
+
+/************************************************************************
+ VARIABLE LENGTH ARRAY TYPE
+ ************************************************************************/
+
+static int
+ng_array_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
+}
+
+static int
+ng_array_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
+}
+
+static int
+ng_array_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int off = 0;
+
+ return ng_parse_composite(type,
+ "[]", &off, start, buf, buflen, CT_ARRAY);
+}
+
+static int
+ng_array_getAlign(const struct ng_parse_type *type)
+{
+ const struct ng_parse_array_info *ai = type->info;
+
+ return ALIGNMENT(ai->elementType);
+}
+
+const struct ng_parse_type ng_parse_array_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_array_parse,
+ ng_array_unparse,
+ ng_array_getDefault,
+ ng_array_getAlign
+};
+
+/************************************************************************
+ INT8 TYPE
+ ************************************************************************/
+
+static int
+ng_int8_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ long val;
+ int8_t val8;
+ char *eptr;
+
+ val = strtol(s + *off, &eptr, 0);
+ if (val < -0x80 || val > 0xff || eptr == s + *off)
+ return (EINVAL);
+ *off = eptr - s;
+ val8 = (int8_t)val;
+ bcopy(&val8, buf, sizeof(int8_t));
+ *buflen = sizeof(int8_t);
+ return (0);
+}
+
+static int
+ng_int8_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ int8_t val;
+
+ bcopy(data + *off, &val, sizeof(int8_t));
+ NG_PARSE_APPEND("%d", (int)val);
+ *off += sizeof(int8_t);
+ return (0);
+}
+
+static int
+ng_int8_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int8_t val;
+
+ if (*buflen < sizeof(int8_t))
+ return (ERANGE);
+ val = 0;
+ bcopy(&val, buf, sizeof(int8_t));
+ *buflen = sizeof(int8_t);
+ return (0);
+}
+
+static int
+ng_int8_getAlign(const struct ng_parse_type *type)
+{
+ return INT8_ALIGNMENT;
+}
+
+const struct ng_parse_type ng_parse_int8_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_int8_parse,
+ ng_int8_unparse,
+ ng_int8_getDefault,
+ ng_int8_getAlign
+};
+
+/************************************************************************
+ INT16 TYPE
+ ************************************************************************/
+
+static int
+ng_int16_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ long val;
+ int16_t val16;
+ char *eptr;
+
+ val = strtol(s + *off, &eptr, 0);
+ if (val < -0x8000 || val > 0xffff || eptr == s + *off)
+ return (EINVAL);
+ *off = eptr - s;
+ val16 = (int16_t)val;
+ bcopy(&val16, buf, sizeof(int16_t));
+ *buflen = sizeof(int16_t);
+ return (0);
+}
+
+static int
+ng_int16_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ int16_t val;
+
+ bcopy(data + *off, &val, sizeof(int16_t));
+ NG_PARSE_APPEND("%d", (int)val);
+ *off += sizeof(int16_t);
+ return (0);
+}
+
+static int
+ng_int16_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int16_t val;
+
+ if (*buflen < sizeof(int16_t))
+ return (ERANGE);
+ val = 0;
+ bcopy(&val, buf, sizeof(int16_t));
+ *buflen = sizeof(int16_t);
+ return (0);
+}
+
+static int
+ng_int16_getAlign(const struct ng_parse_type *type)
+{
+ return INT16_ALIGNMENT;
+}
+
+const struct ng_parse_type ng_parse_int16_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_int16_parse,
+ ng_int16_unparse,
+ ng_int16_getDefault,
+ ng_int16_getAlign
+};
+
+/************************************************************************
+ INT32 TYPE
+ ************************************************************************/
+
+static int
+ng_int32_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ long val; /* assumes long is at least 32 bits */
+ int32_t val32;
+ char *eptr;
+
+ val = strtol(s + *off, &eptr, 0);
+ if (val < -0x80000000 || val > 0xffffffff || eptr == s + *off)
+ return (EINVAL);
+ *off = eptr - s;
+ val32 = (int32_t)val;
+ bcopy(&val32, buf, sizeof(int32_t));
+ *buflen = sizeof(int32_t);
+ return (0);
+}
+
+static int
+ng_int32_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ int32_t val;
+
+ bcopy(data + *off, &val, sizeof(int32_t));
+ NG_PARSE_APPEND("%ld", (long)val);
+ *off += sizeof(int32_t);
+ return (0);
+}
+
+static int
+ng_int32_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int32_t val;
+
+ if (*buflen < sizeof(int32_t))
+ return (ERANGE);
+ val = 0;
+ bcopy(&val, buf, sizeof(int32_t));
+ *buflen = sizeof(int32_t);
+ return (0);
+}
+
+static int
+ng_int32_getAlign(const struct ng_parse_type *type)
+{
+ return INT32_ALIGNMENT;
+}
+
+const struct ng_parse_type ng_parse_int32_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_int32_parse,
+ ng_int32_unparse,
+ ng_int32_getDefault,
+ ng_int32_getAlign
+};
+
+/************************************************************************
+ INT64 TYPE
+ ************************************************************************/
+
+static int
+ng_int64_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ quad_t val;
+ int64_t val64;
+ char *eptr;
+
+ val = strtoq(s + *off, &eptr, 0);
+ if (eptr == s + *off)
+ return (EINVAL);
+ *off = eptr - s;
+ val64 = (int64_t)val;
+ bcopy(&val64, buf, sizeof(int64_t));
+ *buflen = sizeof(int64_t);
+ return (0);
+}
+
+static int
+ng_int64_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ int64_t val;
+
+ bcopy(data + *off, &val, sizeof(int64_t));
+ NG_PARSE_APPEND("%lld", (long long)val);
+ *off += sizeof(int64_t);
+ return (0);
+}
+
+static int
+ng_int64_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ int64_t val;
+
+ if (*buflen < sizeof(int64_t))
+ return (ERANGE);
+ val = 0;
+ bcopy(&val, buf, sizeof(int64_t));
+ *buflen = sizeof(int64_t);
+ return (0);
+}
+
+static int
+ng_int64_getAlign(const struct ng_parse_type *type)
+{
+ return INT64_ALIGNMENT;
+}
+
+const struct ng_parse_type ng_parse_int64_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_int64_parse,
+ ng_int64_unparse,
+ ng_int64_getDefault,
+ ng_int64_getAlign
+};
+
+/************************************************************************
+ STRING TYPE
+ ************************************************************************/
+
+static int
+ng_string_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ char *sval;
+ int len;
+
+ if ((sval = ng_get_string_token(s, off, &len)) == NULL)
+ return (EINVAL);
+ *off += len;
+ len = strlen(sval) + 1;
+ bcopy(sval, buf, len);
+ FREE(sval, M_NETGRAPH);
+ *buflen = len;
+ return (0);
+}
+
+static int
+ng_string_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ const char *const raw = (const char *)data + *off;
+ char *const s = ng_encode_string(raw);
+
+ if (s == NULL)
+ return (ENOMEM);
+ NG_PARSE_APPEND("%s", s);
+ *off += strlen(raw) + 1;
+ FREE(s, M_NETGRAPH);
+ return (0);
+}
+
+static int
+ng_string_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+
+ if (*buflen < 1)
+ return (ERANGE);
+ buf[0] = (u_char)'\0';
+ *buflen = 1;
+ return (0);
+}
+
+const struct ng_parse_type ng_parse_string_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_string_parse,
+ ng_string_unparse,
+ ng_string_getDefault,
+ NULL
+};
+
+/************************************************************************
+ FIXED BUFFER STRING TYPE
+ ************************************************************************/
+
+static int
+ng_fixedstring_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ const struct ng_parse_fixedsstring_info *const fi = type->info;
+ char *sval;
+ int len;
+
+ if ((sval = ng_get_string_token(s, off, &len)) == NULL)
+ return (EINVAL);
+ if (strlen(sval) + 1 > fi->bufSize)
+ return (E2BIG);
+ *off += len;
+ len = strlen(sval) + 1;
+ bcopy(sval, buf, len);
+ FREE(sval, M_NETGRAPH);
+ bzero(buf + len, fi->bufSize - len);
+ *buflen = fi->bufSize;
+ return (0);
+}
+
+static int
+ng_fixedstring_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ const struct ng_parse_fixedsstring_info *const fi = type->info;
+ int error, temp = *off;
+
+ if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
+ return (error);
+ *off += fi->bufSize;
+ return (0);
+}
+
+static int
+ng_fixedstring_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ const struct ng_parse_fixedsstring_info *const fi = type->info;
+
+ if (*buflen < fi->bufSize)
+ return (ERANGE);
+ bzero(buf, fi->bufSize);
+ *buflen = fi->bufSize;
+ return (0);
+}
+
+const struct ng_parse_type ng_parse_fixedstring_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_fixedstring_parse,
+ ng_fixedstring_unparse,
+ ng_fixedstring_getDefault,
+ NULL
+};
+
+const struct ng_parse_fixedsstring_info ng_parse_nodebuf_info = {
+ NG_NODELEN + 1
+};
+const struct ng_parse_type ng_parse_nodebuf_type = {
+ &ng_parse_fixedstring_type,
+ &ng_parse_nodebuf_info
+};
+
+const struct ng_parse_fixedsstring_info ng_parse_hookbuf_info = {
+ NG_HOOKLEN + 1
+};
+const struct ng_parse_type ng_parse_hookbuf_type = {
+ &ng_parse_fixedstring_type,
+ &ng_parse_hookbuf_info
+};
+
+const struct ng_parse_fixedsstring_info ng_parse_pathbuf_info = {
+ NG_PATHLEN + 1
+};
+const struct ng_parse_type ng_parse_pathbuf_type = {
+ &ng_parse_fixedstring_type,
+ &ng_parse_pathbuf_info
+};
+
+const struct ng_parse_fixedsstring_info ng_parse_typebuf_info = {
+ NG_TYPELEN + 1
+};
+const struct ng_parse_type ng_parse_typebuf_type = {
+ &ng_parse_fixedstring_type,
+ &ng_parse_typebuf_info
+};
+
+const struct ng_parse_fixedsstring_info ng_parse_cmdbuf_info = {
+ NG_CMDSTRLEN + 1
+};
+const struct ng_parse_type ng_parse_cmdbuf_type = {
+ &ng_parse_fixedstring_type,
+ &ng_parse_cmdbuf_info
+};
+
+/************************************************************************
+ IP ADDRESS TYPE
+ ************************************************************************/
+
+static int
+ng_ipaddr_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ int i, error;
+
+ for (i = 0; i < 4; i++) {
+ if ((error = ng_int8_parse(&ng_parse_int8_type,
+ s, off, start, buf + i, buflen)) != 0)
+ return (error);
+ if (i < 3 && s[*off] != '.')
+ return (EINVAL);
+ (*off)++;
+ }
+ *buflen = 4;
+ return (0);
+}
+
+static int
+ng_ipaddr_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ struct in_addr ip;
+
+ bcopy(data + *off, &ip, sizeof(ip));
+ NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
+ ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
+ *off += sizeof(ip);
+ return (0);
+}
+
+static int
+ng_ipaddr_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ struct in_addr ip = { 0 };
+
+ if (*buflen < sizeof(ip))
+ return (ERANGE);
+ bcopy(&ip, buf, sizeof(ip));
+ *buflen = sizeof(ip);
+ return (0);
+}
+
+const struct ng_parse_type ng_parse_ipaddr_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_ipaddr_parse,
+ ng_ipaddr_unparse,
+ ng_ipaddr_getDefault,
+ ng_int32_getAlign
+};
+
+/************************************************************************
+ BYTE ARRAY TYPE
+ ************************************************************************/
+
+/* Get the length of a byte array */
+static int
+ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ ng_parse_array_getLength_t *const getLength = type->private;
+
+ return (*getLength)(type, start, buf);
+}
+
+static int
+ng_bytearray_elem_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ int8_t val;
+
+ bcopy(data + *off, &val, sizeof(int8_t));
+ NG_PARSE_APPEND("0x%02x", (int)val & 0xff); /* always hex format */
+ *off += sizeof(int8_t);
+ return (0);
+}
+
+/* Byte array element type is int8, but always output in hex format */
+const struct ng_parse_type ng_parse_bytearray_elem_type = {
+ &ng_parse_int8_type,
+ NULL,
+ NULL,
+ NULL,
+ ng_bytearray_elem_unparse,
+ NULL,
+ NULL
+};
+
+static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
+ &ng_parse_bytearray_elem_type,
+ &ng_parse_bytearray_subtype_getLength,
+ NULL
+};
+static const struct ng_parse_type ng_parse_bytearray_subtype = {
+ &ng_parse_array_type,
+ &ng_parse_bytearray_subtype_info
+};
+
+static int
+ng_bytearray_parse(const struct ng_parse_type *type,
+ const char *s, int *off, const u_char *const start,
+ u_char *const buf, int *buflen)
+{
+ char *str;
+ int toklen;
+
+ /* We accept either an array of bytes or a string constant */
+ if ((str = ng_get_string_token(s, off, &toklen)) != NULL) {
+ ng_parse_array_getLength_t *const getLength = type->info;
+ int arraylen, slen;
+
+ arraylen = (*getLength)(type, start, buf);
+ if (arraylen > *buflen) {
+ FREE(str, M_NETGRAPH);
+ return (ERANGE);
+ }
+ slen = strlen(str) + 1;
+ if (slen > arraylen) {
+ FREE(str, M_NETGRAPH);
+ return (E2BIG);
+ }
+ bcopy(str, buf, slen);
+ bzero(buf + slen, arraylen - slen);
+ FREE(str, M_NETGRAPH);
+ *off += toklen;
+ *buflen = arraylen;
+ return (0);
+ } else {
+ struct ng_parse_type subtype;
+
+ subtype = ng_parse_bytearray_subtype;
+ (const void *)subtype.private = type->info;
+ return ng_array_parse(&subtype, s, off, start, buf, buflen);
+ }
+}
+
+static int
+ng_bytearray_unparse(const struct ng_parse_type *type,
+ const u_char *data, int *off, char *cbuf, int cbuflen)
+{
+ struct ng_parse_type subtype;
+
+ subtype = ng_parse_bytearray_subtype;
+ (const void *)subtype.private = type->info;
+ return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
+}
+
+static int
+ng_bytearray_getDefault(const struct ng_parse_type *type,
+ const u_char *const start, u_char *buf, int *buflen)
+{
+ struct ng_parse_type subtype;
+
+ subtype = ng_parse_bytearray_subtype;
+ (const void *)subtype.private = type->info;
+ return ng_array_getDefault(&subtype, start, buf, buflen);
+}
+
+const struct ng_parse_type ng_parse_bytearray_type = {
+ NULL,
+ NULL,
+ NULL,
+ ng_bytearray_parse,
+ ng_bytearray_unparse,
+ ng_bytearray_getDefault,
+ NULL
+};
+
+/************************************************************************
+ STRUCT NG_MESG TYPE
+ ************************************************************************/
+
+/* Get msg->header.arglen when "buf" is pointing to msg->data */
+static int
+ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
+ const u_char *start, const u_char *buf)
+{
+ const struct ng_mesg *msg;
+
+ msg = (const struct ng_mesg *)(buf - sizeof(*msg));
+ return msg->header.arglen;
+}
+
+/* Type for the variable length data portion of a struct ng_mesg */
+static const struct ng_parse_type ng_msg_data_type = {
+ &ng_parse_bytearray_type,
+ &ng_parse_ng_mesg_getLength
+};
+
+/* Type for the entire struct ng_mesg header with data section */
+static const struct ng_parse_struct_info
+ ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
+const struct ng_parse_type ng_parse_ng_mesg_type = {
+ &ng_parse_struct_type,
+ &ng_parse_ng_mesg_type_info,
+};
+
+/************************************************************************
+ COMPOSITE HELPER ROUTINES
+ ************************************************************************/
+
+/*
+ * Convert a structure or array from ASCII to binary
+ */
+static int
+ng_parse_composite(const struct ng_parse_type *type, const char *s,
+ int *off, const u_char *const start, u_char *const buf, int *buflen,
+ const enum comptype ctype)
+{
+ const int num = ng_get_composite_len(type, start, buf, ctype);
+ int nextIndex = 0; /* next implicit array index */
+ u_int index; /* field or element index */
+ int *foff; /* field value offsets in string */
+ int align, len, blen, error = 0;
+
+ /* Initialize */
+ MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT);
+ if (foff == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+ bzero(foff, num * sizeof(*foff));
+
+ /* Get opening brace/bracket */
+ if (ng_parse_get_token(s, off, &len)
+ != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
+ error = EINVAL;
+ goto done;
+ }
+ *off += len;
+
+ /* Get individual element value positions in the string */
+ for (;;) {
+ enum ng_parse_token tok;
+
+ /* Check for closing brace/bracket */
+ tok = ng_parse_get_token(s, off, &len);
+ if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
+ *off += len;
+ break;
+ }
+
+ /* For arrays, the 'name' (ie, index) is optional, so
+ distinguish name from values by seeing if the next
+ token is an equals sign */
+ if (ctype != CT_STRUCT) {
+ int len2, off2;
+ char *eptr;
+
+ /* If an opening brace/bracket, index is implied */
+ if (tok == T_LBRACE || tok == T_LBRACKET) {
+ index = nextIndex++;
+ goto gotIndex;
+ }
+
+ /* Might be an index, might be a value, either way... */
+ if (tok != T_WORD) {
+ error = EINVAL;
+ goto done;
+ }
+
+ /* If no equals sign follows, index is implied */
+ off2 = *off + len;
+ if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
+ index = nextIndex++;
+ goto gotIndex;
+ }
+
+ /* Index was specified explicitly; parse it */
+ index = (u_int)strtoul(s + *off, &eptr, 0);
+ if (index < 0 || eptr - (s + *off) != len) {
+ error = EINVAL;
+ goto done;
+ }
+ nextIndex = index + 1;
+ *off += len + len2;
+gotIndex:
+ } else { /* a structure field */
+ const struct ng_parse_struct_field *field = NULL;
+ const struct ng_parse_struct_info *si = type->info;
+
+ /* Find the field by name (required) in field list */
+ if (tok != T_WORD) {
+ error = EINVAL;
+ goto done;
+ }
+ for (index = 0; index < num; index++) {
+ field = &si->fields[index];
+ if (strncmp(&s[*off], field->name, len) == 0
+ && field->name[len] == '\0')
+ break;
+ }
+ if (index == num) {
+ error = ENOENT;
+ goto done;
+ }
+ *off += len;
+
+ /* Get equals sign */
+ if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
+ error = EINVAL;
+ goto done;
+ }
+ *off += len;
+ }
+
+ /* Check array index */
+ if (index >= num) {
+ error = E2BIG;
+ goto done;
+ }
+
+ /* Save value's position and skip over it for now */
+ if (foff[index] != 0) {
+ error = EALREADY; /* duplicate */
+ goto done;
+ }
+ while (isspace(s[*off]))
+ (*off)++;
+ foff[index] = *off;
+ if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
+ goto done;
+ *off += len;
+ }
+
+ /* Now build binary structure from supplied values and defaults */
+ for (blen = index = 0; index < num; index++) {
+ const struct ng_parse_type *const
+ etype = ng_get_composite_etype(type, index, ctype);
+ int k, pad, vlen;
+
+ /* Zero-pad any alignment bytes */
+ pad = ng_parse_get_elem_pad(type, index, ctype, blen);
+ for (k = 0; k < pad; k++) {
+ if (blen >= *buflen) {
+ error = ERANGE;
+ goto done;
+ }
+ buf[blen++] = 0;
+ }
+
+ /* Get value */
+ vlen = *buflen - blen;
+ if (foff[index] == 0) { /* use default value */
+ error = ng_get_composite_elem_default(type, index,
+ start, buf + blen, &vlen, ctype);
+ } else { /* parse given value */
+ *off = foff[index];
+ error = INVOKE(etype, parse)(etype,
+ s, off, start, buf + blen, &vlen);
+ }
+ if (error != 0)
+ goto done;
+ blen += vlen;
+ }
+
+ /* Make total composite structure size a multiple of its alignment */
+ if ((align = ALIGNMENT(type)) != 0) {
+ while (blen % align != 0) {
+ if (blen >= *buflen) {
+ error = ERANGE;
+ goto done;
+ }
+ buf[blen++] = 0;
+ }
+ }
+
+ /* Done */
+ *buflen = blen;
+done:
+ FREE(foff, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Convert an array or structure from binary to ASCII
+ */
+static int
+ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
+ int *off, char *cbuf, int cbuflen, const enum comptype ctype)
+{
+ const int num = ng_get_composite_len(type, data, data + *off, ctype);
+ int nextIndex = 0, didOne = 0;
+ int error, index;
+
+ /* Opening brace/bracket */
+ NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
+
+ /* Do each item */
+ for (index = 0; index < num; index++) {
+ const struct ng_parse_type *const
+ etype = ng_get_composite_etype(type, index, ctype);
+ u_char temp[1024];
+
+ /* Skip any alignment pad bytes */
+ *off += ng_parse_get_elem_pad(type, index, ctype, *off);
+
+ /* See if element is equal to its default value; skip if so */
+ if (*off < sizeof(temp)) {
+ int tempsize = sizeof(temp) - *off;
+
+ bcopy(data, temp, *off);
+ if (ng_get_composite_elem_default(type, index, temp,
+ temp + *off, &tempsize, ctype) == 0
+ && bcmp(temp + *off, data + *off, tempsize) == 0) {
+ *off += tempsize;
+ continue;
+ }
+ }
+
+ /* Print name= */
+ NG_PARSE_APPEND(" ");
+ if (ctype != CT_STRUCT) {
+ if (index != nextIndex) {
+ nextIndex = index;
+ NG_PARSE_APPEND("%d=", index);
+ }
+ nextIndex++;
+ } else {
+ const struct ng_parse_struct_info *si = type->info;
+
+ NG_PARSE_APPEND("%s=", si->fields[index].name);
+ }
+
+ /* Print value */
+ if ((error = INVOKE(etype, unparse)
+ (etype, data, off, cbuf, cbuflen)) != 0)
+ return (error);
+ cbuflen -= strlen(cbuf);
+ cbuf += strlen(cbuf);
+ didOne = 1;
+ }
+
+ /* Closing brace/bracket */
+ NG_PARSE_APPEND("%s%c",
+ didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
+ return (0);
+}
+
+/*
+ * Generate the default value for an element of an array or structure
+ * Returns EOPNOTSUPP if default value is unspecified.
+ */
+static int
+ng_get_composite_elem_default(const struct ng_parse_type *type,
+ int index, const u_char *const start, u_char *buf, int *buflen,
+ const enum comptype ctype)
+{
+ const struct ng_parse_type *etype;
+ ng_getDefault_t *func;
+
+ switch (ctype) {
+ case CT_STRUCT:
+ break;
+ case CT_ARRAY:
+ {
+ const struct ng_parse_array_info *const ai = type->info;
+
+ if (ai->getDefault != NULL) {
+ return (*ai->getDefault)(type,
+ index, start, buf, buflen);
+ }
+ break;
+ }
+ case CT_FIXEDARRAY:
+ {
+ const struct ng_parse_fixedarray_info *const fi = type->info;
+
+ if (*fi->getDefault != NULL) {
+ return (*fi->getDefault)(type,
+ index, start, buf, buflen);
+ }
+ break;
+ }
+ default:
+ panic("%s", __FUNCTION__);
+ }
+
+ /* Default to element type default */
+ etype = ng_get_composite_etype(type, index, ctype);
+ func = METHOD(etype, getDefault);
+ if (func == NULL)
+ return (EOPNOTSUPP);
+ return (*func)(etype, start, buf, buflen);
+}
+
+/*
+ * Get the number of elements in a struct, variable or fixed array.
+ */
+static int
+ng_get_composite_len(const struct ng_parse_type *type,
+ const u_char *const start, const u_char *buf,
+ const enum comptype ctype)
+{
+ switch (ctype) {
+ case CT_STRUCT:
+ {
+ const struct ng_parse_struct_info *const si = type->info;
+ int numFields = 0;
+
+ for (numFields = 0; ; numFields++) {
+ const struct ng_parse_struct_field *const
+ fi = &si->fields[numFields];
+
+ if (fi->name == NULL)
+ break;
+ }
+ return (numFields);
+ }
+ case CT_ARRAY:
+ {
+ const struct ng_parse_array_info *const ai = type->info;
+
+ return (*ai->getLength)(type, start, buf);
+ }
+ case CT_FIXEDARRAY:
+ {
+ const struct ng_parse_fixedarray_info *const fi = type->info;
+
+ return fi->length;
+ }
+ default:
+ panic("%s", __FUNCTION__);
+ }
+ return (0);
+}
+
+/*
+ * Return the type of the index'th element of a composite structure
+ */
+static const struct ng_parse_type *
+ng_get_composite_etype(const struct ng_parse_type *type,
+ int index, const enum comptype ctype)
+{
+ const struct ng_parse_type *etype = NULL;
+
+ switch (ctype) {
+ case CT_STRUCT:
+ {
+ const struct ng_parse_struct_info *const si = type->info;
+
+ etype = si->fields[index].type;
+ break;
+ }
+ case CT_ARRAY:
+ {
+ const struct ng_parse_array_info *const ai = type->info;
+
+ etype = ai->elementType;
+ break;
+ }
+ case CT_FIXEDARRAY:
+ {
+ const struct ng_parse_fixedarray_info *const fi = type->info;
+
+ etype = fi->elementType;
+ break;
+ }
+ default:
+ panic("%s", __FUNCTION__);
+ }
+ return (etype);
+}
+
+/*
+ * Get the number of bytes to skip to align for the next
+ * element in a composite structure.
+ */
+static int
+ng_parse_get_elem_pad(const struct ng_parse_type *type,
+ int index, enum comptype ctype, int posn)
+{
+ const struct ng_parse_type *const
+ etype = ng_get_composite_etype(type, index, ctype);
+ int align;
+
+ /* Get element's alignment, and possibly override */
+ align = ALIGNMENT(etype);
+ if (ctype == CT_STRUCT) {
+ const struct ng_parse_struct_info *si = type->info;
+
+ if (si->fields[index].alignment != 0)
+ align = si->fields[index].alignment;
+ }
+
+ /* Return number of bytes to skip to align */
+ return (align ? (align - (posn % align)) % align : 0);
+}
+
+/************************************************************************
+ PARSING HELPER ROUTINES
+ ************************************************************************/
+
+/*
+ * Skip over a value
+ */
+static int
+ng_parse_skip_value(const char *s, int off0, int *lenp)
+{
+ int len, nbracket, nbrace;
+ int off = off0;
+
+ len = nbracket = nbrace = 0;
+ do {
+ switch (ng_parse_get_token(s, &off, &len)) {
+ case T_LBRACKET:
+ nbracket++;
+ break;
+ case T_LBRACE:
+ nbrace++;
+ break;
+ case T_RBRACKET:
+ if (nbracket-- == 0)
+ return (EINVAL);
+ break;
+ case T_RBRACE:
+ if (nbrace-- == 0)
+ return (EINVAL);
+ break;
+ case T_EOF:
+ return (EINVAL);
+ default:
+ break;
+ }
+ off += len;
+ } while (nbracket > 0 || nbrace > 0);
+ *lenp = off - off0;
+ return (0);
+}
+
+/*
+ * Find the next token in the string, starting at offset *startp.
+ * Returns the token type, with *startp pointing to the first char
+ * and *lenp the length.
+ */
+enum ng_parse_token
+ng_parse_get_token(const char *s, int *startp, int *lenp)
+{
+ char *t;
+ int i;
+
+ while (isspace(s[*startp]))
+ (*startp)++;
+ switch (s[*startp]) {
+ case '\0':
+ *lenp = 0;
+ return T_EOF;
+ case '{':
+ *lenp = 1;
+ return T_LBRACE;
+ case '}':
+ *lenp = 1;
+ return T_RBRACE;
+ case '[':
+ *lenp = 1;
+ return T_LBRACKET;
+ case ']':
+ *lenp = 1;
+ return T_RBRACKET;
+ case '=':
+ *lenp = 1;
+ return T_EQUALS;
+ case '"':
+ if ((t = ng_get_string_token(s, startp, lenp)) == NULL)
+ return T_ERROR;
+ FREE(t, M_NETGRAPH);
+ return T_STRING;
+ default:
+ for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
+ && s[i] != '{' && s[i] != '}' && s[i] != '['
+ && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
+ ;
+ *lenp = i - *startp;
+ return T_WORD;
+ }
+}
+
+/*
+ * Get a string token, which must be enclosed in double quotes.
+ * The normal C backslash escapes are recognized.
+ */
+char *
+ng_get_string_token(const char *s, int *startp, int *lenp)
+{
+ char *cbuf, *p;
+ int start, off;
+
+ while (isspace(s[*startp]))
+ (*startp)++;
+ start = *startp;
+ if (s[*startp] != '"')
+ return (NULL);
+ MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT);
+ if (cbuf == NULL)
+ return (NULL);
+ strcpy(cbuf, s + start + 1);
+ for (off = 1, p = cbuf; *p != '\0'; off++, p++) {
+ if (*p == '"') {
+ *p = '\0';
+ *lenp = off + 1;
+ return (cbuf);
+ } else if (p[0] == '\\' && p[1] != '\0') {
+ int x, k;
+ char *v;
+
+ strcpy(p, p + 1);
+ v = p;
+ switch (*p) {
+ case 't':
+ *v = '\t';
+ off++;
+ continue;
+ case 'n':
+ *v = '\n';
+ off++;
+ continue;
+ case 'r':
+ *v = '\r';
+ off++;
+ continue;
+ case 'v':
+ *v = '\v';
+ off++;
+ continue;
+ case 'f':
+ *v = '\f';
+ off++;
+ continue;
+ case '"':
+ *v = '"';
+ off++;
+ continue;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ for (x = k = 0;
+ k < 3 && *v >= '0' && *v <= '7'; v++) {
+ x = (x << 3) + (*v - '0');
+ off++;
+ }
+ *--v = (char)x;
+ break;
+ case 'x':
+ for (v++, x = k = 0;
+ k < 2 && isxdigit(*v); v++) {
+ x = (x << 4) + (isdigit(*v) ?
+ (*v - '0') :
+ (tolower(*v) - 'a' + 10));
+ off++;
+ }
+ *--v = (char)x;
+ break;
+ default:
+ continue;
+ }
+ strcpy(p, v);
+ }
+ }
+ return (NULL); /* no closing quote */
+}
+
+/*
+ * Encode a string so it can be safely put in double quotes.
+ * Caller must free the result.
+ */
+char *
+ng_encode_string(const char *raw)
+{
+ char *cbuf;
+ int off = 0;
+
+ MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT);
+ if (cbuf == NULL)
+ return (NULL);
+ cbuf[off++] = '"';
+ for ( ; *raw != '\0'; raw++) {
+ switch (*raw) {
+ case '\t':
+ cbuf[off++] = '\\';
+ cbuf[off++] = 't';
+ break;
+ case '\f':
+ cbuf[off++] = '\\';
+ cbuf[off++] = 'f';
+ break;
+ case '\n':
+ cbuf[off++] = '\\';
+ cbuf[off++] = 'n';
+ break;
+ case '\r':
+ cbuf[off++] = '\\';
+ cbuf[off++] = 'r';
+ break;
+ case '\v':
+ cbuf[off++] = '\\';
+ cbuf[off++] = 'v';
+ break;
+ case '"':
+ case '\\':
+ cbuf[off++] = '\\';
+ cbuf[off++] = *raw;
+ break;
+ default:
+ if (*raw < 0x20 || *raw > 0x7e) {
+ off += sprintf(cbuf + off,
+ "\\x%02x", (u_char)*raw);
+ break;
+ }
+ cbuf[off++] = *raw;
+ break;
+ }
+ }
+ cbuf[off++] = '"';
+ cbuf[off] = '\0';
+ return (cbuf);
+}
+
+/************************************************************************
+ VIRTUAL METHOD LOOKUP
+ ************************************************************************/
+
+static ng_parse_t *
+ng_get_parse_method(const struct ng_parse_type *t)
+{
+ while (t != NULL && t->parse == NULL)
+ t = t->supertype;
+ return (t ? t->parse : NULL);
+}
+
+static ng_unparse_t *
+ng_get_unparse_method(const struct ng_parse_type *t)
+{
+ while (t != NULL && t->unparse == NULL)
+ t = t->supertype;
+ return (t ? t->unparse : NULL);
+}
+
+static ng_getDefault_t *
+ng_get_getDefault_method(const struct ng_parse_type *t)
+{
+ while (t != NULL && t->getDefault == NULL)
+ t = t->supertype;
+ return (t ? t->getDefault : NULL);
+}
+
+static ng_getAlign_t *
+ng_get_getAlign_method(const struct ng_parse_type *t)
+{
+ while (t != NULL && t->getAlign == NULL)
+ t = t->supertype;
+ return (t ? t->getAlign : NULL);
+}
+
diff --git a/sys/netgraph/ng_parse.h b/sys/netgraph/ng_parse.h
new file mode 100644
index 0000000..1efbdbe
--- /dev/null
+++ b/sys/netgraph/ng_parse.h
@@ -0,0 +1,388 @@
+
+/*
+ * 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 <archie@whistle.com>
+ *
+ * $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.
+
+ Syntax
+ ------
+
+ Structures:
+
+ '{' [ <name>=<value> ... ] '}'
+
+ Omitted fields have their default values by implication.
+ The order in which the fields are specified does not matter.
+
+ Arrays:
+
+ '[' [ [index=]<value> ... ] ']'
+
+ Element value may be specified with or without the "<index>=" 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.
+
+ Example
+ -------
+
+ Structure Binary (big endian)
+ --------- -------------------
+
+ 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
+ };
+
+ ASCII form: "{ ip=3.3.3.3 num=3 ary=[ 5 2=10 ] }"
+
+ 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").
+
+ 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: { } [ ] = "
+
+*/
+
+/************************************************************************
+ 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.
+ */
+
+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.
+ */
+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
+ *
+ * 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
+ *
+ * Default value: See below
+ * 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);
+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
+ *
+ * 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;
+
+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
+ *
+ * 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.
+ *
+ * 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
+ */
+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
+ *
+ * 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
+ *
+ * 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.
+ *
+ * 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
+ *
+ * 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_ */
+
diff --git a/sys/netgraph/ng_ppp.c b/sys/netgraph/ng_ppp.c
index 2097de1..7cfb4b6 100644
--- a/sys/netgraph/ng_ppp.c
+++ b/sys/netgraph/ng_ppp.c
@@ -57,6 +57,7 @@
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
#include <netgraph/ng_ppp.h>
#include <netgraph/ng_vjc.h>
@@ -205,6 +206,78 @@ static int ng_ppp_config_valid(node_p node,
static void ng_ppp_update(node_p node, int newConf);
static void ng_ppp_free_frags(node_p node);
+/* Parse type for struct ng_ppp_link_config */
+static const struct ng_parse_struct_info
+ ng_ppp_link_type_info = NG_PPP_LINK_TYPE_INFO;
+static const struct ng_parse_type ng_ppp_link_type = {
+ &ng_parse_struct_type,
+ &ng_ppp_link_type_info,
+};
+
+/* Parse type for struct ng_ppp_node_config */
+struct ng_parse_fixedarray_info ng_ppp_array_info = {
+ &ng_ppp_link_type,
+ NG_PPP_MAX_LINKS
+};
+static const struct ng_parse_type ng_ppp_link_array_type = {
+ &ng_parse_fixedarray_type,
+ &ng_ppp_array_info,
+};
+static const struct ng_parse_struct_info ng_ppp_config_type_info
+ = NG_PPP_CONFIG_TYPE_INFO(&ng_ppp_link_array_type);
+static const struct ng_parse_type ng_ppp_config_type = {
+ &ng_parse_struct_type,
+ &ng_ppp_config_type_info
+};
+
+/* Parse type for struct ng_ppp_link_stat */
+static const struct ng_parse_struct_info
+ ng_ppp_stats_type_info = NG_PPP_STATS_TYPE_INFO;
+static const struct ng_parse_type ng_ppp_stats_type = {
+ &ng_parse_struct_type,
+ &ng_ppp_stats_type_info
+};
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_ppp_cmds[] = {
+ {
+ NGM_PPP_COOKIE,
+ NGM_PPP_SET_CONFIG,
+ "setconfig",
+ &ng_ppp_config_type,
+ NULL
+ },
+ {
+ NGM_PPP_COOKIE,
+ NGM_PPP_GET_CONFIG,
+ "getconfig",
+ NULL,
+ &ng_ppp_config_type
+ },
+ {
+ NGM_PPP_COOKIE,
+ NGM_PPP_GET_LINK_STATS,
+ "getstats",
+ &ng_parse_int16_type,
+ &ng_ppp_stats_type
+ },
+ {
+ NGM_PPP_COOKIE,
+ NGM_PPP_CLR_LINK_STATS,
+ "clrstats",
+ &ng_parse_int16_type,
+ NULL
+ },
+ {
+ NGM_PPP_COOKIE,
+ NGM_PPP_GETCLR_LINK_STATS,
+ "getclrstats",
+ &ng_parse_int16_type,
+ &ng_ppp_stats_type
+ },
+ { 0 }
+};
+
/* Node type descriptor */
static struct ng_type ng_ppp_typestruct = {
NG_VERSION,
@@ -218,7 +291,8 @@ static struct ng_type ng_ppp_typestruct = {
NULL,
ng_ppp_rcvdata,
ng_ppp_rcvdata,
- ng_ppp_disconnect
+ ng_ppp_disconnect,
+ ng_ppp_cmds
};
NETGRAPH_INIT(ppp, &ng_ppp_typestruct);
@@ -334,7 +408,7 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
case NGM_PPP_SET_CONFIG:
{
struct ng_ppp_node_config *const newConf =
- (struct ng_ppp_node_config *) msg->data;
+ (struct ng_ppp_node_config *) msg->data;
/* Check for invalid or illegal config */
if (msg->header.arglen != sizeof(*newConf))
diff --git a/sys/netgraph/ng_ppp.h b/sys/netgraph/ng_ppp.h
index 7962746..c32b5a31 100644
--- a/sys/netgraph/ng_ppp.h
+++ b/sys/netgraph/ng_ppp.h
@@ -92,6 +92,19 @@ struct ng_ppp_link_config {
u_int32_t bandwidth; /* link bandwidth (in bytes/second) */
};
+/* Keep this in sync with the above structure definition */
+#define NG_PPP_LINK_TYPE_INFO { \
+ { \
+ { "enable", &ng_parse_int8_type }, \
+ { "protocomp", &ng_parse_int8_type }, \
+ { "acfcomp", &ng_parse_int8_type }, \
+ { "mru", &ng_parse_int16_type }, \
+ { "latency", &ng_parse_int32_type }, \
+ { "bandwidth", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
/* Node config structure */
struct ng_ppp_node_config {
u_int16_t mrru; /* multilink peer MRRU */
@@ -112,6 +125,28 @@ struct ng_ppp_node_config {
links[NG_PPP_MAX_LINKS];
};
+/* Keep this in sync with the above structure definition */
+#define NG_PPP_CONFIG_TYPE_INFO(arytype) { \
+ { \
+ { "mrru", &ng_parse_int16_type }, \
+ { "multilink", &ng_parse_int8_type }, \
+ { "recvShortSeq", &ng_parse_int8_type }, \
+ { "xmitShortSeq", &ng_parse_int8_type }, \
+ { "roundRobin", &ng_parse_int8_type }, \
+ { "ip", &ng_parse_int8_type }, \
+ { "appletalk", &ng_parse_int8_type }, \
+ { "ipx", &ng_parse_int8_type }, \
+ { "comp", &ng_parse_int8_type }, \
+ { "decomp", &ng_parse_int8_type }, \
+ { "encryption", &ng_parse_int8_type }, \
+ { "decryption", &ng_parse_int8_type }, \
+ { "vjcomp", &ng_parse_int8_type }, \
+ { "vjdecomp", &ng_parse_int8_type }, \
+ { "links", (arytype) }, \
+ { NULL }, \
+ } \
+}
+
/* Statistics struct for a link (or the bundle if NG_PPP_BUNDLE_LINKNUM) */
struct ng_ppp_link_stat {
u_int32_t xmitFrames; /* xmit frames on link */
@@ -122,4 +157,17 @@ struct ng_ppp_link_stat {
u_int32_t dupFragments; /* MP frames with duplicate seq # */
};
+/* Keep this in sync with the above structure definition */
+#define NG_PPP_STATS_TYPE_INFO { \
+ { \
+ { "xmitFrames", &ng_parse_int32_type }, \
+ { "xmitOctets", &ng_parse_int32_type }, \
+ { "recvFrames", &ng_parse_int32_type }, \
+ { "recvOctets", &ng_parse_int32_type }, \
+ { "badProtos", &ng_parse_int32_type }, \
+ { "dupFragments", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
#endif /* _NETGRAPH_PPP_H_ */
diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c
index 6499e8f..836b295 100644
--- a/sys/netgraph/ng_pppoe.c
+++ b/sys/netgraph/ng_pppoe.c
@@ -88,7 +88,8 @@ static struct ng_type typestruct = {
ng_pppoe_connect,
ng_pppoe_rcvdata,
ng_pppoe_rcvdata,
- ng_pppoe_disconnect
+ ng_pppoe_disconnect,
+ NULL
};
NETGRAPH_INIT(pppoe, &typestruct);
diff --git a/sys/netgraph/ng_rfc1490.c b/sys/netgraph/ng_rfc1490.c
index 6cd20a5..13c3d2d 100644
--- a/sys/netgraph/ng_rfc1490.c
+++ b/sys/netgraph/ng_rfc1490.c
@@ -109,7 +109,8 @@ static struct ng_type typestruct = {
NULL,
ng_rfc1490_rcvdata,
ng_rfc1490_rcvdata,
- ng_rfc1490_disconnect
+ ng_rfc1490_disconnect,
+ NULL
};
NETGRAPH_INIT(rfc1490, &typestruct);
diff --git a/sys/netgraph/ng_rfc1490.h b/sys/netgraph/ng_rfc1490.h
index 98cdf63..494a60f 100644
--- a/sys/netgraph/ng_rfc1490.h
+++ b/sys/netgraph/ng_rfc1490.h
@@ -45,7 +45,7 @@
/* Node type name */
#define NG_RFC1490_NODE_TYPE "rfc1490"
-#define NGM_RFC1490_NODE_COOKIE 861060632
+#define NGM_RFC1490_COOKIE 861060632
/* Hook names */
#define NG_RFC1490_HOOK_DOWNSTREAM "downstream"
diff --git a/sys/netgraph/ng_sample.c b/sys/netgraph/ng_sample.c
index 5c68ad9..688cd81 100644
--- a/sys/netgraph/ng_sample.c
+++ b/sys/netgraph/ng_sample.c
@@ -79,7 +79,8 @@ static struct ng_type typestruct = {
ng_xxx_connect,
ng_xxx_rcvdata,
ng_xxx_rcvdataq,
- ng_xxx_disconnect
+ ng_xxx_disconnect,
+ NULL
};
NETGRAPH_INIT(xxx, &typestruct);
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c
index 321037a..d783687 100644
--- a/sys/netgraph/ng_socket.c
+++ b/sys/netgraph/ng_socket.c
@@ -133,7 +133,8 @@ static struct ng_type typestruct = {
NULL,
ngs_rcvdata,
ngs_rcvdata,
- ngs_disconnect
+ ngs_disconnect,
+ NULL
};
NETGRAPH_INIT(socket, &typestruct);
diff --git a/sys/netgraph/ng_tee.c b/sys/netgraph/ng_tee.c
index 7ae417c..2c5b9f3 100644
--- a/sys/netgraph/ng_tee.c
+++ b/sys/netgraph/ng_tee.c
@@ -96,7 +96,8 @@ static struct ng_type typestruct = {
NULL,
ngt_rcvdata,
ngt_rcvdata,
- ngt_disconnect
+ ngt_disconnect,
+ NULL
};
NETGRAPH_INIT(tee, &typestruct);
diff --git a/sys/netgraph/ng_tty.c b/sys/netgraph/ng_tty.c
index 2d3a1c4..9b5568f 100644
--- a/sys/netgraph/ng_tty.c
+++ b/sys/netgraph/ng_tty.c
@@ -89,15 +89,15 @@
/* Per-node private info */
struct ngt_sc {
- struct tty *tp; /* Terminal device */
- node_p node; /* Netgraph node */
- hook_p hook; /* Netgraph hook */
- struct mbuf *m; /* Incoming data buffer */
- struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */
- short qlen; /* Length of queue */
- short hotchar; /* Hotchar, or -1 if none */
- u_int flags; /* Flags */
- struct callout_handle chand; /* See man timeout(9) */
+ struct tty *tp; /* Terminal device */
+ node_p node; /* Netgraph node */
+ hook_p hook; /* Netgraph hook */
+ struct mbuf *m; /* Incoming data buffer */
+ struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */
+ short qlen; /* Length of queue */
+ short hotchar; /* Hotchar, or -1 if none */
+ u_int flags; /* Flags */
+ struct callout_handle chand; /* See man timeout(9) */
};
typedef struct ngt_sc *sc_p;
@@ -106,7 +106,7 @@ typedef struct ngt_sc *sc_p;
#define FLG_DEBUG 0x0002
/* Debugging */
-#ifdef DIAGNOSTICS
+#ifdef INVARIANTS
#define QUEUECHECK(sc) \
do { \
struct mbuf **mp; \
@@ -173,6 +173,7 @@ static struct ng_type typestruct = {
ngt_rcvdata,
ngt_rcvdata,
ngt_disconnect,
+ NULL
};
NETGRAPH_INIT(tty, &typestruct);
diff --git a/sys/netgraph/ng_vjc.c b/sys/netgraph/ng_vjc.c
index db96f1c..b572600 100644
--- a/sys/netgraph/ng_vjc.c
+++ b/sys/netgraph/ng_vjc.c
@@ -112,7 +112,8 @@ static struct ng_type typestruct = {
NULL,
ng_vjc_rcvdata,
ng_vjc_rcvdata,
- ng_vjc_disconnect
+ ng_vjc_disconnect,
+ NULL
};
NETGRAPH_INIT(vjc, &typestruct);
OpenPOWER on IntegriCloud