aboutsummaryrefslogtreecommitdiff
path: root/sys/netgraph/ng_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netgraph/ng_base.c')
-rw-r--r--sys/netgraph/ng_base.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index 84cd69625086..7d20e80a4705 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