14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * ng_base.c 44cf49a43SJulian Elischer * 54cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 64cf49a43SJulian Elischer * All rights reserved. 74cf49a43SJulian Elischer * 84cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 94cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 104cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 114cf49a43SJulian Elischer * provided, however, that: 124cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 134cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 144cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 154cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 164cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 174cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 184cf49a43SJulian Elischer * 194cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 204cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 214cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 224cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 234cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 244cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 254cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 264cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 274cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 284cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 294cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 304cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 314cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 324cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 334cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 344cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 354cf49a43SJulian Elischer * OF SUCH DAMAGE. 364cf49a43SJulian Elischer * 37cc3bbd68SJulian Elischer * Authors: Julian Elischer <julian@freebsd.org> 38cc3bbd68SJulian Elischer * Archie Cobbs <archie@freebsd.org> 394cf49a43SJulian Elischer * 404cf49a43SJulian Elischer * $FreeBSD$ 414cf49a43SJulian Elischer * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 424cf49a43SJulian Elischer */ 434cf49a43SJulian Elischer 444cf49a43SJulian Elischer /* 454cf49a43SJulian Elischer * This file implements the base netgraph code. 464cf49a43SJulian Elischer */ 474cf49a43SJulian Elischer 484cf49a43SJulian Elischer #include <sys/param.h> 494cf49a43SJulian Elischer #include <sys/systm.h> 504cf49a43SJulian Elischer #include <sys/errno.h> 514cf49a43SJulian Elischer #include <sys/kernel.h> 524cf49a43SJulian Elischer #include <sys/malloc.h> 534cf49a43SJulian Elischer #include <sys/syslog.h> 544cf49a43SJulian Elischer #include <sys/linker.h> 554cf49a43SJulian Elischer #include <sys/queue.h> 564cf49a43SJulian Elischer #include <sys/mbuf.h> 575b664c7cSPoul-Henning Kamp #include <sys/ctype.h> 582b70adcbSArchie Cobbs #include <machine/limits.h> 594cf49a43SJulian Elischer 604cf49a43SJulian Elischer #include <net/netisr.h> 614cf49a43SJulian Elischer 624cf49a43SJulian Elischer #include <netgraph/ng_message.h> 634cf49a43SJulian Elischer #include <netgraph/netgraph.h> 64f8307e12SArchie Cobbs #include <netgraph/ng_parse.h> 654cf49a43SJulian Elischer 6699ff8176SPeter Wemm MODULE_VERSION(netgraph, 1); 6799ff8176SPeter Wemm 684cf49a43SJulian Elischer /* List of all nodes */ 69e3975643SJake Burkholder static LIST_HEAD(, ng_node) nodelist; 704cf49a43SJulian Elischer 714cf49a43SJulian Elischer /* List of installed types */ 72e3975643SJake Burkholder static LIST_HEAD(, ng_type) typelist; 734cf49a43SJulian Elischer 74dc90cad9SJulian Elischer /* Hash releted definitions */ 75dc90cad9SJulian Elischer #define ID_HASH_SIZE 32 /* most systems wont need even this many */ 76e3975643SJake Burkholder static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE]; 77dc90cad9SJulian Elischer /* Don't nead to initialise them because it's a LIST */ 78dc90cad9SJulian Elischer 794cf49a43SJulian Elischer /* Internal functions */ 804cf49a43SJulian Elischer static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 814cf49a43SJulian Elischer static int ng_connect(hook_p hook1, hook_p hook2); 824cf49a43SJulian Elischer static void ng_disconnect_hook(hook_p hook); 834cf49a43SJulian Elischer static int ng_generic_msg(node_p here, struct ng_mesg *msg, 84a4ec03cfSJulian Elischer const char *retaddr, struct ng_mesg ** resp, 85a4ec03cfSJulian Elischer hook_p hook); 86dc90cad9SJulian Elischer static ng_ID_t ng_decodeidname(const char *name); 874cf49a43SJulian Elischer static int ngb_mod_event(module_t mod, int event, void *data); 88859a4d16SJulian Elischer static int ng_send_data_dont_queue(hook_p hook, struct mbuf *m, 89859a4d16SJulian Elischer meta_p meta, struct mbuf **ret_m, meta_p *ret_meta, 90859a4d16SJulian Elischer struct ng_mesg **resp); 914cf49a43SJulian Elischer static void ngintr(void); 924cf49a43SJulian Elischer 934cf49a43SJulian Elischer /* Our own netgraph malloc type */ 944cf49a43SJulian Elischer MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 954cf49a43SJulian Elischer 964cf49a43SJulian Elischer /* Set this to Debugger("X") to catch all errors as they occur */ 974cf49a43SJulian Elischer #ifndef TRAP_ERROR 984cf49a43SJulian Elischer #define TRAP_ERROR 994cf49a43SJulian Elischer #endif 1004cf49a43SJulian Elischer 101dc90cad9SJulian Elischer static ng_ID_t nextID = 1; 102dc90cad9SJulian Elischer 103b2da83c2SArchie Cobbs #ifdef INVARIANTS 104b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) do { \ 105b2da83c2SArchie Cobbs struct mbuf *n; \ 106b2da83c2SArchie Cobbs int total; \ 107b2da83c2SArchie Cobbs \ 108b2da83c2SArchie Cobbs if (((m)->m_flags & M_PKTHDR) == 0) \ 109b2da83c2SArchie Cobbs panic("%s: !PKTHDR", __FUNCTION__); \ 110b2da83c2SArchie Cobbs for (total = 0, n = (m); n != NULL; n = n->m_next) \ 111b2da83c2SArchie Cobbs total += n->m_len; \ 112b2da83c2SArchie Cobbs if ((m)->m_pkthdr.len != total) { \ 113b2da83c2SArchie Cobbs panic("%s: %d != %d", \ 114b2da83c2SArchie Cobbs __FUNCTION__, (m)->m_pkthdr.len, total); \ 115b2da83c2SArchie Cobbs } \ 116b2da83c2SArchie Cobbs } while (0) 117b2da83c2SArchie Cobbs #else 118b2da83c2SArchie Cobbs #define CHECK_DATA_MBUF(m) 119b2da83c2SArchie Cobbs #endif 120b2da83c2SArchie Cobbs 121dc90cad9SJulian Elischer 1224cf49a43SJulian Elischer /************************************************************************ 123f8307e12SArchie Cobbs Parse type definitions for generic messages 124f8307e12SArchie Cobbs ************************************************************************/ 125f8307e12SArchie Cobbs 126f8307e12SArchie Cobbs /* Handy structure parse type defining macro */ 127f8307e12SArchie Cobbs #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 128f8307e12SArchie Cobbs static const struct ng_parse_struct_info \ 129f8307e12SArchie Cobbs ng_ ## lo ## _type_info = NG_GENERIC_ ## up ## _INFO args; \ 130f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 131f8307e12SArchie Cobbs &ng_parse_struct_type, \ 132f8307e12SArchie Cobbs &ng_ ## lo ## _type_info \ 133f8307e12SArchie Cobbs } 134f8307e12SArchie Cobbs 135f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 136f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 137f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 138f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 139f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 140f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 141f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 142f8307e12SArchie Cobbs 143f8307e12SArchie Cobbs /* Get length of an array when the length is stored as a 32 bit 144f8307e12SArchie Cobbs value immediately preceeding the array -- as with struct namelist 145f8307e12SArchie Cobbs and struct typelist. */ 146f8307e12SArchie Cobbs static int 147f8307e12SArchie Cobbs ng_generic_list_getLength(const struct ng_parse_type *type, 148f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 149f8307e12SArchie Cobbs { 150f8307e12SArchie Cobbs return *((const u_int32_t *)(buf - 4)); 151f8307e12SArchie Cobbs } 152f8307e12SArchie Cobbs 153f8307e12SArchie Cobbs /* Get length of the array of struct linkinfo inside a struct hooklist */ 154f8307e12SArchie Cobbs static int 155f8307e12SArchie Cobbs ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 156f8307e12SArchie Cobbs const u_char *start, const u_char *buf) 157f8307e12SArchie Cobbs { 158f8307e12SArchie Cobbs const struct hooklist *hl = (const struct hooklist *)start; 159f8307e12SArchie Cobbs 160f8307e12SArchie Cobbs return hl->nodeinfo.hooks; 161f8307e12SArchie Cobbs } 162f8307e12SArchie Cobbs 163f8307e12SArchie Cobbs /* Array type for a variable length array of struct namelist */ 164f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 165f8307e12SArchie Cobbs &ng_generic_nodeinfo_type, 166f8307e12SArchie Cobbs &ng_generic_list_getLength 167f8307e12SArchie Cobbs }; 168f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 169f8307e12SArchie Cobbs &ng_parse_array_type, 170f8307e12SArchie Cobbs &ng_nodeinfoarray_type_info 171f8307e12SArchie Cobbs }; 172f8307e12SArchie Cobbs 173f8307e12SArchie Cobbs /* Array type for a variable length array of struct typelist */ 174f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 175f8307e12SArchie Cobbs &ng_generic_typeinfo_type, 176f8307e12SArchie Cobbs &ng_generic_list_getLength 177f8307e12SArchie Cobbs }; 178f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_typeinfoarray_type = { 179f8307e12SArchie Cobbs &ng_parse_array_type, 180f8307e12SArchie Cobbs &ng_typeinfoarray_type_info 181f8307e12SArchie Cobbs }; 182f8307e12SArchie Cobbs 183f8307e12SArchie Cobbs /* Array type for array of struct linkinfo in struct hooklist */ 184f8307e12SArchie Cobbs static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 185f8307e12SArchie Cobbs &ng_generic_linkinfo_type, 186f8307e12SArchie Cobbs &ng_generic_linkinfo_getLength 187f8307e12SArchie Cobbs }; 188f8307e12SArchie Cobbs static const struct ng_parse_type ng_generic_linkinfo_array_type = { 189f8307e12SArchie Cobbs &ng_parse_array_type, 190f8307e12SArchie Cobbs &ng_generic_linkinfo_array_type_info 191f8307e12SArchie Cobbs }; 192f8307e12SArchie Cobbs 193f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 194f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 195f8307e12SArchie Cobbs (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 196f8307e12SArchie Cobbs DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 197f8307e12SArchie Cobbs (&ng_generic_nodeinfoarray_type)); 198f8307e12SArchie Cobbs 199f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 200f8307e12SArchie Cobbs static const struct ng_cmdlist ng_generic_cmds[] = { 201f8307e12SArchie Cobbs { 202f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 203f8307e12SArchie Cobbs NGM_SHUTDOWN, 204f8307e12SArchie Cobbs "shutdown", 205f8307e12SArchie Cobbs NULL, 206f8307e12SArchie Cobbs NULL 207f8307e12SArchie Cobbs }, 208f8307e12SArchie Cobbs { 209f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 210f8307e12SArchie Cobbs NGM_MKPEER, 211f8307e12SArchie Cobbs "mkpeer", 212f8307e12SArchie Cobbs &ng_generic_mkpeer_type, 213f8307e12SArchie Cobbs NULL 214f8307e12SArchie Cobbs }, 215f8307e12SArchie Cobbs { 216f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 217f8307e12SArchie Cobbs NGM_CONNECT, 218f8307e12SArchie Cobbs "connect", 219f8307e12SArchie Cobbs &ng_generic_connect_type, 220f8307e12SArchie Cobbs NULL 221f8307e12SArchie Cobbs }, 222f8307e12SArchie Cobbs { 223f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 224f8307e12SArchie Cobbs NGM_NAME, 225f8307e12SArchie Cobbs "name", 226f8307e12SArchie Cobbs &ng_generic_name_type, 227f8307e12SArchie Cobbs NULL 228f8307e12SArchie Cobbs }, 229f8307e12SArchie Cobbs { 230f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 231f8307e12SArchie Cobbs NGM_RMHOOK, 232f8307e12SArchie Cobbs "rmhook", 233f8307e12SArchie Cobbs &ng_generic_rmhook_type, 234f8307e12SArchie Cobbs NULL 235f8307e12SArchie Cobbs }, 236f8307e12SArchie Cobbs { 237f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 238f8307e12SArchie Cobbs NGM_NODEINFO, 239f8307e12SArchie Cobbs "nodeinfo", 240f8307e12SArchie Cobbs NULL, 241f8307e12SArchie Cobbs &ng_generic_nodeinfo_type 242f8307e12SArchie Cobbs }, 243f8307e12SArchie Cobbs { 244f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 245f8307e12SArchie Cobbs NGM_LISTHOOKS, 246f8307e12SArchie Cobbs "listhooks", 247f8307e12SArchie Cobbs NULL, 248f8307e12SArchie Cobbs &ng_generic_hooklist_type 249f8307e12SArchie Cobbs }, 250f8307e12SArchie Cobbs { 251f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 252f8307e12SArchie Cobbs NGM_LISTNAMES, 253f8307e12SArchie Cobbs "listnames", 254f8307e12SArchie Cobbs NULL, 255f8307e12SArchie Cobbs &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 256f8307e12SArchie Cobbs }, 257f8307e12SArchie Cobbs { 258f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 259f8307e12SArchie Cobbs NGM_LISTNODES, 260f8307e12SArchie Cobbs "listnodes", 261f8307e12SArchie Cobbs NULL, 262f8307e12SArchie Cobbs &ng_generic_listnodes_type 263f8307e12SArchie Cobbs }, 264f8307e12SArchie Cobbs { 265f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 266f8307e12SArchie Cobbs NGM_LISTTYPES, 267f8307e12SArchie Cobbs "listtypes", 268f8307e12SArchie Cobbs NULL, 269f8307e12SArchie Cobbs &ng_generic_typeinfo_type 270f8307e12SArchie Cobbs }, 271f8307e12SArchie Cobbs { 272f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 2737095e097SPoul-Henning Kamp NGM_TEXT_CONFIG, 2747095e097SPoul-Henning Kamp "textconfig", 2757095e097SPoul-Henning Kamp NULL, 2767095e097SPoul-Henning Kamp &ng_parse_string_type 2777095e097SPoul-Henning Kamp }, 2787095e097SPoul-Henning Kamp { 2797095e097SPoul-Henning Kamp NGM_GENERIC_COOKIE, 280f8307e12SArchie Cobbs NGM_TEXT_STATUS, 281f8307e12SArchie Cobbs "textstatus", 282f8307e12SArchie Cobbs NULL, 283f8307e12SArchie Cobbs &ng_parse_string_type 284f8307e12SArchie Cobbs }, 285f8307e12SArchie Cobbs { 286f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 287f8307e12SArchie Cobbs NGM_ASCII2BINARY, 288f8307e12SArchie Cobbs "ascii2binary", 289f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 290f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 291f8307e12SArchie Cobbs }, 292f8307e12SArchie Cobbs { 293f8307e12SArchie Cobbs NGM_GENERIC_COOKIE, 294f8307e12SArchie Cobbs NGM_BINARY2ASCII, 295f8307e12SArchie Cobbs "binary2ascii", 296f8307e12SArchie Cobbs &ng_parse_ng_mesg_type, 297f8307e12SArchie Cobbs &ng_parse_ng_mesg_type 298f8307e12SArchie Cobbs }, 299f8307e12SArchie Cobbs { 0 } 300f8307e12SArchie Cobbs }; 301f8307e12SArchie Cobbs 302f8307e12SArchie Cobbs /************************************************************************ 3034cf49a43SJulian Elischer Node routines 3044cf49a43SJulian Elischer ************************************************************************/ 3054cf49a43SJulian Elischer 3064cf49a43SJulian Elischer /* 3074cf49a43SJulian Elischer * Instantiate a node of the requested type 3084cf49a43SJulian Elischer */ 3094cf49a43SJulian Elischer int 3104cf49a43SJulian Elischer ng_make_node(const char *typename, node_p *nodepp) 3114cf49a43SJulian Elischer { 3124cf49a43SJulian Elischer struct ng_type *type; 3134cf49a43SJulian Elischer 3144cf49a43SJulian Elischer /* Check that the type makes sense */ 3154cf49a43SJulian Elischer if (typename == NULL) { 3164cf49a43SJulian Elischer TRAP_ERROR; 3174cf49a43SJulian Elischer return (EINVAL); 3184cf49a43SJulian Elischer } 3194cf49a43SJulian Elischer 3204cf49a43SJulian Elischer /* Locate the node type */ 3214cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) { 322cc3daab5SPeter Wemm char filename[NG_TYPELEN + 4]; 3234cf49a43SJulian Elischer linker_file_t lf; 3244cf49a43SJulian Elischer int error; 3254cf49a43SJulian Elischer 3264cf49a43SJulian Elischer /* Not found, try to load it as a loadable module */ 327859a4d16SJulian Elischer snprintf(filename, sizeof(filename), "/boot/kernel/ng_%s", typename); 328cc3daab5SPeter Wemm error = linker_load_file(filename, &lf); 3294cf49a43SJulian Elischer if (error != 0) 3304cf49a43SJulian Elischer return (error); 3314cf49a43SJulian Elischer lf->userrefs++; /* pretend loaded by the syscall */ 3324cf49a43SJulian Elischer 3334cf49a43SJulian Elischer /* Try again, as now the type should have linked itself in */ 3344cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) 3354cf49a43SJulian Elischer return (ENXIO); 3364cf49a43SJulian Elischer } 3374cf49a43SJulian Elischer 3384cf49a43SJulian Elischer /* Call the constructor */ 3394cf49a43SJulian Elischer if (type->constructor != NULL) 3404cf49a43SJulian Elischer return ((*type->constructor)(nodepp)); 3414cf49a43SJulian Elischer else 3424cf49a43SJulian Elischer return (ng_make_node_common(type, nodepp)); 3434cf49a43SJulian Elischer } 3444cf49a43SJulian Elischer 3454cf49a43SJulian Elischer /* 3464cf49a43SJulian Elischer * Generic node creation. Called by node constructors. 3474cf49a43SJulian Elischer * The returned node has a reference count of 1. 3484cf49a43SJulian Elischer */ 3494cf49a43SJulian Elischer int 3504cf49a43SJulian Elischer ng_make_node_common(struct ng_type *type, node_p *nodepp) 3514cf49a43SJulian Elischer { 3524cf49a43SJulian Elischer node_p node; 3534cf49a43SJulian Elischer 3544cf49a43SJulian Elischer /* Require the node type to have been already installed */ 3554cf49a43SJulian Elischer if (ng_findtype(type->name) == NULL) { 3564cf49a43SJulian Elischer TRAP_ERROR; 3574cf49a43SJulian Elischer return (EINVAL); 3584cf49a43SJulian Elischer } 3594cf49a43SJulian Elischer 3604cf49a43SJulian Elischer /* Make a node and try attach it to the type */ 36199cdf4ccSDavid Malone MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_NOWAIT | M_ZERO); 3624cf49a43SJulian Elischer if (node == NULL) { 3634cf49a43SJulian Elischer TRAP_ERROR; 3644cf49a43SJulian Elischer return (ENOMEM); 3654cf49a43SJulian Elischer } 3664cf49a43SJulian Elischer node->type = type; 3674cf49a43SJulian Elischer node->refs++; /* note reference */ 3684cf49a43SJulian Elischer type->refs++; 3694cf49a43SJulian Elischer 3704cf49a43SJulian Elischer /* Link us into the node linked list */ 3714cf49a43SJulian Elischer LIST_INSERT_HEAD(&nodelist, node, nodes); 3724cf49a43SJulian Elischer 3734cf49a43SJulian Elischer /* Initialize hook list for new node */ 3744cf49a43SJulian Elischer LIST_INIT(&node->hooks); 3754cf49a43SJulian Elischer 376dc90cad9SJulian Elischer /* get an ID and put us in the hash chain */ 377dc90cad9SJulian Elischer node->ID = nextID++; /* 137 per second for 1 year before wrap */ 378dc90cad9SJulian Elischer LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes); 379dc90cad9SJulian Elischer 3804cf49a43SJulian Elischer /* Done */ 3814cf49a43SJulian Elischer *nodepp = node; 3824cf49a43SJulian Elischer return (0); 3834cf49a43SJulian Elischer } 3844cf49a43SJulian Elischer 3854cf49a43SJulian Elischer /* 3864cf49a43SJulian Elischer * Forceably start the shutdown process on a node. Either call 3874cf49a43SJulian Elischer * it's shutdown method, or do the default shutdown if there is 3884cf49a43SJulian Elischer * no type-specific method. 3894cf49a43SJulian Elischer * 3904cf49a43SJulian Elischer * Persistent nodes must have a type-specific method which 3914cf49a43SJulian Elischer * resets the NG_INVALID flag. 3924cf49a43SJulian Elischer */ 3934cf49a43SJulian Elischer void 3944cf49a43SJulian Elischer ng_rmnode(node_p node) 3954cf49a43SJulian Elischer { 3964cf49a43SJulian Elischer /* Check if it's already shutting down */ 3974cf49a43SJulian Elischer if ((node->flags & NG_INVALID) != 0) 3984cf49a43SJulian Elischer return; 3994cf49a43SJulian Elischer 4004cf49a43SJulian Elischer /* Add an extra reference so it doesn't go away during this */ 4014cf49a43SJulian Elischer node->refs++; 4024cf49a43SJulian Elischer 4034cf49a43SJulian Elischer /* Mark it invalid so any newcomers know not to try use it */ 4044cf49a43SJulian Elischer node->flags |= NG_INVALID; 4054cf49a43SJulian Elischer 4064cf49a43SJulian Elischer /* Ask the type if it has anything to do in this case */ 4074cf49a43SJulian Elischer if (node->type && node->type->shutdown) 4084cf49a43SJulian Elischer (*node->type->shutdown)(node); 4094cf49a43SJulian Elischer else { /* do the default thing */ 4104cf49a43SJulian Elischer ng_unname(node); 4114cf49a43SJulian Elischer ng_cutlinks(node); 4124cf49a43SJulian Elischer ng_unref(node); 4134cf49a43SJulian Elischer } 4144cf49a43SJulian Elischer 4154cf49a43SJulian Elischer /* Remove extra reference, possibly the last */ 4164cf49a43SJulian Elischer ng_unref(node); 4174cf49a43SJulian Elischer } 4184cf49a43SJulian Elischer 4194cf49a43SJulian Elischer /* 4204cf49a43SJulian Elischer * Called by the destructor to remove any STANDARD external references 4214cf49a43SJulian Elischer */ 4224cf49a43SJulian Elischer void 4234cf49a43SJulian Elischer ng_cutlinks(node_p node) 4244cf49a43SJulian Elischer { 4254cf49a43SJulian Elischer hook_p hook; 4264cf49a43SJulian Elischer 4274cf49a43SJulian Elischer /* Make sure that this is set to stop infinite loops */ 4284cf49a43SJulian Elischer node->flags |= NG_INVALID; 4294cf49a43SJulian Elischer 4304cf49a43SJulian Elischer /* If we have sleepers, wake them up; they'll see NG_INVALID */ 4314cf49a43SJulian Elischer if (node->sleepers) 4324cf49a43SJulian Elischer wakeup(node); 4334cf49a43SJulian Elischer 4344cf49a43SJulian Elischer /* Notify all remaining connected nodes to disconnect */ 4354cf49a43SJulian Elischer while ((hook = LIST_FIRST(&node->hooks)) != NULL) 4364cf49a43SJulian Elischer ng_destroy_hook(hook); 4374cf49a43SJulian Elischer } 4384cf49a43SJulian Elischer 4394cf49a43SJulian Elischer /* 4404cf49a43SJulian Elischer * Remove a reference to the node, possibly the last 4414cf49a43SJulian Elischer */ 4424cf49a43SJulian Elischer void 4434cf49a43SJulian Elischer ng_unref(node_p node) 4444cf49a43SJulian Elischer { 445e8a49db2SJulian Elischer int s; 446e8a49db2SJulian Elischer 447e8a49db2SJulian Elischer s = splhigh(); 4484cf49a43SJulian Elischer if (--node->refs <= 0) { 4494cf49a43SJulian Elischer node->type->refs--; 4504cf49a43SJulian Elischer LIST_REMOVE(node, nodes); 451dc90cad9SJulian Elischer LIST_REMOVE(node, idnodes); 4524cf49a43SJulian Elischer FREE(node, M_NETGRAPH); 4534cf49a43SJulian Elischer } 454e8a49db2SJulian Elischer splx(s); 4554cf49a43SJulian Elischer } 4564cf49a43SJulian Elischer 4574cf49a43SJulian Elischer /* 4584cf49a43SJulian Elischer * Wait for a node to come ready. Returns a node with a reference count; 4594cf49a43SJulian Elischer * don't forget to drop it when we are done with it using ng_release_node(). 4604cf49a43SJulian Elischer */ 4614cf49a43SJulian Elischer int 4624cf49a43SJulian Elischer ng_wait_node(node_p node, char *msg) 4634cf49a43SJulian Elischer { 4644cf49a43SJulian Elischer int s, error = 0; 4654cf49a43SJulian Elischer 4664cf49a43SJulian Elischer if (msg == NULL) 4674cf49a43SJulian Elischer msg = "netgraph"; 4684cf49a43SJulian Elischer s = splnet(); 4694cf49a43SJulian Elischer node->sleepers++; 4704cf49a43SJulian Elischer node->refs++; /* the sleeping process counts as a reference */ 4714cf49a43SJulian Elischer while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY) 4724cf49a43SJulian Elischer error = tsleep(node, (PZERO + 1) | PCATCH, msg, 0); 4734cf49a43SJulian Elischer node->sleepers--; 4744cf49a43SJulian Elischer if (node->flags & NG_INVALID) { 4754cf49a43SJulian Elischer TRAP_ERROR; 4764cf49a43SJulian Elischer error = ENXIO; 4774cf49a43SJulian Elischer } else { 478b2da83c2SArchie Cobbs KASSERT(node->refs > 1, 479b2da83c2SArchie Cobbs ("%s: refs=%d", __FUNCTION__, node->refs)); 4804cf49a43SJulian Elischer node->flags |= NG_BUSY; 4814cf49a43SJulian Elischer } 4824cf49a43SJulian Elischer splx(s); 4834cf49a43SJulian Elischer 4844cf49a43SJulian Elischer /* Release the reference we had on it */ 4854cf49a43SJulian Elischer if (error != 0) 4864cf49a43SJulian Elischer ng_unref(node); 4874cf49a43SJulian Elischer return error; 4884cf49a43SJulian Elischer } 4894cf49a43SJulian Elischer 4904cf49a43SJulian Elischer /* 4914cf49a43SJulian Elischer * Release a node acquired via ng_wait_node() 4924cf49a43SJulian Elischer */ 4934cf49a43SJulian Elischer void 4944cf49a43SJulian Elischer ng_release_node(node_p node) 4954cf49a43SJulian Elischer { 4964cf49a43SJulian Elischer /* Declare that we don't want it */ 4974cf49a43SJulian Elischer node->flags &= ~NG_BUSY; 4984cf49a43SJulian Elischer 4994cf49a43SJulian Elischer /* If we have sleepers, then wake them up */ 5004cf49a43SJulian Elischer if (node->sleepers) 5014cf49a43SJulian Elischer wakeup(node); 5024cf49a43SJulian Elischer 5034cf49a43SJulian Elischer /* We also have a reference.. drop it too */ 5044cf49a43SJulian Elischer ng_unref(node); 5054cf49a43SJulian Elischer } 5064cf49a43SJulian Elischer 5074cf49a43SJulian Elischer /************************************************************************ 508dc90cad9SJulian Elischer Node ID handling 509dc90cad9SJulian Elischer ************************************************************************/ 510dc90cad9SJulian Elischer static node_p 511dc90cad9SJulian Elischer ng_ID2node(ng_ID_t ID) 512dc90cad9SJulian Elischer { 513dc90cad9SJulian Elischer node_p np; 514dc90cad9SJulian Elischer LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) { 515dc90cad9SJulian Elischer if (np->ID == ID) 516dc90cad9SJulian Elischer break; 517dc90cad9SJulian Elischer } 518dc90cad9SJulian Elischer return(np); 519dc90cad9SJulian Elischer } 520dc90cad9SJulian Elischer 521dc90cad9SJulian Elischer ng_ID_t 522dc90cad9SJulian Elischer ng_node2ID(node_p node) 523dc90cad9SJulian Elischer { 524dc90cad9SJulian Elischer return (node->ID); 525dc90cad9SJulian Elischer } 526dc90cad9SJulian Elischer 527dc90cad9SJulian Elischer /************************************************************************ 5284cf49a43SJulian Elischer Node name handling 5294cf49a43SJulian Elischer ************************************************************************/ 5304cf49a43SJulian Elischer 5314cf49a43SJulian Elischer /* 5324cf49a43SJulian Elischer * Assign a node a name. Once assigned, the name cannot be changed. 5334cf49a43SJulian Elischer */ 5344cf49a43SJulian Elischer int 5354cf49a43SJulian Elischer ng_name_node(node_p node, const char *name) 5364cf49a43SJulian Elischer { 5374cf49a43SJulian Elischer int i; 5384cf49a43SJulian Elischer 5394cf49a43SJulian Elischer /* Check the name is valid */ 5404cf49a43SJulian Elischer for (i = 0; i < NG_NODELEN + 1; i++) { 5414cf49a43SJulian Elischer if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 5424cf49a43SJulian Elischer break; 5434cf49a43SJulian Elischer } 5444cf49a43SJulian Elischer if (i == 0 || name[i] != '\0') { 5454cf49a43SJulian Elischer TRAP_ERROR; 5464cf49a43SJulian Elischer return (EINVAL); 5474cf49a43SJulian Elischer } 548dc90cad9SJulian Elischer if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 5494cf49a43SJulian Elischer TRAP_ERROR; 5504cf49a43SJulian Elischer return (EINVAL); 5514cf49a43SJulian Elischer } 5524cf49a43SJulian Elischer 5534cf49a43SJulian Elischer /* Check the node isn't already named */ 5544cf49a43SJulian Elischer if (node->name != NULL) { 5554cf49a43SJulian Elischer TRAP_ERROR; 5564cf49a43SJulian Elischer return (EISCONN); 5574cf49a43SJulian Elischer } 5584cf49a43SJulian Elischer 5594cf49a43SJulian Elischer /* Check the name isn't already being used */ 5604cf49a43SJulian Elischer if (ng_findname(node, name) != NULL) { 5614cf49a43SJulian Elischer TRAP_ERROR; 5624cf49a43SJulian Elischer return (EADDRINUSE); 5634cf49a43SJulian Elischer } 5644cf49a43SJulian Elischer 5654cf49a43SJulian Elischer /* Allocate space and copy it */ 566d2ea40c2SArchie Cobbs MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT); 5674cf49a43SJulian Elischer if (node->name == NULL) { 5684cf49a43SJulian Elischer TRAP_ERROR; 5694cf49a43SJulian Elischer return (ENOMEM); 5704cf49a43SJulian Elischer } 5714cf49a43SJulian Elischer strcpy(node->name, name); 5724cf49a43SJulian Elischer 5734cf49a43SJulian Elischer /* The name counts as a reference */ 5744cf49a43SJulian Elischer node->refs++; 5754cf49a43SJulian Elischer return (0); 5764cf49a43SJulian Elischer } 5774cf49a43SJulian Elischer 5784cf49a43SJulian Elischer /* 5794cf49a43SJulian Elischer * Find a node by absolute name. The name should NOT end with ':' 5804cf49a43SJulian Elischer * The name "." means "this node" and "[xxx]" means "the node 5814cf49a43SJulian Elischer * with ID (ie, at address) xxx". 5824cf49a43SJulian Elischer * 5834cf49a43SJulian Elischer * Returns the node if found, else NULL. 5844cf49a43SJulian Elischer */ 5854cf49a43SJulian Elischer node_p 5864cf49a43SJulian Elischer ng_findname(node_p this, const char *name) 5874cf49a43SJulian Elischer { 588dc90cad9SJulian Elischer node_p node; 589dc90cad9SJulian Elischer ng_ID_t temp; 5904cf49a43SJulian Elischer 5914cf49a43SJulian Elischer /* "." means "this node" */ 5924cf49a43SJulian Elischer if (strcmp(name, ".") == 0) 5934cf49a43SJulian Elischer return(this); 5944cf49a43SJulian Elischer 5954cf49a43SJulian Elischer /* Check for name-by-ID */ 596dc90cad9SJulian Elischer if ((temp = ng_decodeidname(name)) != 0) { 597dc90cad9SJulian Elischer return (ng_ID2node(temp)); 5984cf49a43SJulian Elischer } 5994cf49a43SJulian Elischer 6004cf49a43SJulian Elischer /* Find node by name */ 6014cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 6024cf49a43SJulian Elischer if (node->name != NULL && strcmp(node->name, name) == 0) 6034cf49a43SJulian Elischer break; 6044cf49a43SJulian Elischer } 6054cf49a43SJulian Elischer return (node); 6064cf49a43SJulian Elischer } 6074cf49a43SJulian Elischer 6084cf49a43SJulian Elischer /* 609dc90cad9SJulian Elischer * Decode a ID name, eg. "[f03034de]". Returns 0 if the 610dc90cad9SJulian Elischer * string is not valid, otherwise returns the value. 6114cf49a43SJulian Elischer */ 612dc90cad9SJulian Elischer static ng_ID_t 6134cf49a43SJulian Elischer ng_decodeidname(const char *name) 6144cf49a43SJulian Elischer { 6152b70adcbSArchie Cobbs const int len = strlen(name); 61625792ef3SArchie Cobbs char *eptr; 6172b70adcbSArchie Cobbs u_long val; 6184cf49a43SJulian Elischer 6192b70adcbSArchie Cobbs /* Check for proper length, brackets, no leading junk */ 6202b70adcbSArchie Cobbs if (len < 3 || name[0] != '[' || name[len - 1] != ']' 621ef050c81SJulian Elischer || !isxdigit(name[1])) 6222b70adcbSArchie Cobbs return (0); 6234cf49a43SJulian Elischer 6242b70adcbSArchie Cobbs /* Decode number */ 6252b70adcbSArchie Cobbs val = strtoul(name + 1, &eptr, 16); 626ef050c81SJulian Elischer if (eptr - name != len - 1 || val == ULONG_MAX || val == 0) 62712f035e0SJulian Elischer return ((ng_ID_t)0); 6282b70adcbSArchie Cobbs return (ng_ID_t)val; 6294cf49a43SJulian Elischer } 6304cf49a43SJulian Elischer 6314cf49a43SJulian Elischer /* 6324cf49a43SJulian Elischer * Remove a name from a node. This should only be called 6334cf49a43SJulian Elischer * when shutting down and removing the node. 6344cf49a43SJulian Elischer */ 6354cf49a43SJulian Elischer void 6364cf49a43SJulian Elischer ng_unname(node_p node) 6374cf49a43SJulian Elischer { 6384cf49a43SJulian Elischer if (node->name) { 6394cf49a43SJulian Elischer FREE(node->name, M_NETGRAPH); 6404cf49a43SJulian Elischer node->name = NULL; 6414cf49a43SJulian Elischer ng_unref(node); 6424cf49a43SJulian Elischer } 6434cf49a43SJulian Elischer } 6444cf49a43SJulian Elischer 6454cf49a43SJulian Elischer /************************************************************************ 6464cf49a43SJulian Elischer Hook routines 6474cf49a43SJulian Elischer 6484cf49a43SJulian Elischer Names are not optional. Hooks are always connected, except for a 6494cf49a43SJulian Elischer brief moment within these routines. 6504cf49a43SJulian Elischer 6514cf49a43SJulian Elischer ************************************************************************/ 6524cf49a43SJulian Elischer 6534cf49a43SJulian Elischer /* 6544cf49a43SJulian Elischer * Remove a hook reference 6554cf49a43SJulian Elischer */ 6564cf49a43SJulian Elischer static void 6574cf49a43SJulian Elischer ng_unref_hook(hook_p hook) 6584cf49a43SJulian Elischer { 659e8a49db2SJulian Elischer int s; 660e8a49db2SJulian Elischer 661e8a49db2SJulian Elischer s = splhigh(); 6624cf49a43SJulian Elischer if (--hook->refs == 0) 6634cf49a43SJulian Elischer FREE(hook, M_NETGRAPH); 664e8a49db2SJulian Elischer splx(s); 6654cf49a43SJulian Elischer } 6664cf49a43SJulian Elischer 6674cf49a43SJulian Elischer /* 6684cf49a43SJulian Elischer * Add an unconnected hook to a node. Only used internally. 6694cf49a43SJulian Elischer */ 6704cf49a43SJulian Elischer static int 6714cf49a43SJulian Elischer ng_add_hook(node_p node, const char *name, hook_p *hookp) 6724cf49a43SJulian Elischer { 6734cf49a43SJulian Elischer hook_p hook; 6744cf49a43SJulian Elischer int error = 0; 6754cf49a43SJulian Elischer 6764cf49a43SJulian Elischer /* Check that the given name is good */ 6774cf49a43SJulian Elischer if (name == NULL) { 6784cf49a43SJulian Elischer TRAP_ERROR; 6794cf49a43SJulian Elischer return (EINVAL); 6804cf49a43SJulian Elischer } 681899e9c4eSArchie Cobbs if (ng_findhook(node, name) != NULL) { 6824cf49a43SJulian Elischer TRAP_ERROR; 6834cf49a43SJulian Elischer return (EEXIST); 6844cf49a43SJulian Elischer } 6854cf49a43SJulian Elischer 6864cf49a43SJulian Elischer /* Allocate the hook and link it up */ 68799cdf4ccSDavid Malone MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_NOWAIT | M_ZERO); 6884cf49a43SJulian Elischer if (hook == NULL) { 6894cf49a43SJulian Elischer TRAP_ERROR; 6904cf49a43SJulian Elischer return (ENOMEM); 6914cf49a43SJulian Elischer } 6924cf49a43SJulian Elischer hook->refs = 1; 6934cf49a43SJulian Elischer hook->flags = HK_INVALID; 6944cf49a43SJulian Elischer hook->node = node; 6954cf49a43SJulian Elischer node->refs++; /* each hook counts as a reference */ 6964cf49a43SJulian Elischer 6974cf49a43SJulian Elischer /* Check if the node type code has something to say about it */ 6984cf49a43SJulian Elischer if (node->type->newhook != NULL) 6994cf49a43SJulian Elischer if ((error = (*node->type->newhook)(node, hook, name)) != 0) 7004cf49a43SJulian Elischer goto fail; 7014cf49a43SJulian Elischer 7024cf49a43SJulian Elischer /* 7034cf49a43SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 7044cf49a43SJulian Elischer * We'll ask again later when we actually connect the hooks. 7054cf49a43SJulian Elischer */ 7064cf49a43SJulian Elischer LIST_INSERT_HEAD(&node->hooks, hook, hooks); 7074cf49a43SJulian Elischer node->numhooks++; 7084cf49a43SJulian Elischer 7094cf49a43SJulian Elischer /* Set hook name */ 710d2ea40c2SArchie Cobbs MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT); 7114cf49a43SJulian Elischer if (hook->name == NULL) { 7124cf49a43SJulian Elischer error = ENOMEM; 7134cf49a43SJulian Elischer LIST_REMOVE(hook, hooks); 7144cf49a43SJulian Elischer node->numhooks--; 7154cf49a43SJulian Elischer fail: 7164cf49a43SJulian Elischer hook->node = NULL; 7174cf49a43SJulian Elischer ng_unref(node); 7184cf49a43SJulian Elischer ng_unref_hook(hook); /* this frees the hook */ 7194cf49a43SJulian Elischer return (error); 7204cf49a43SJulian Elischer } 7214cf49a43SJulian Elischer strcpy(hook->name, name); 7224cf49a43SJulian Elischer if (hookp) 7234cf49a43SJulian Elischer *hookp = hook; 7244cf49a43SJulian Elischer return (error); 7254cf49a43SJulian Elischer } 7264cf49a43SJulian Elischer 7274cf49a43SJulian Elischer /* 7284cf49a43SJulian Elischer * Connect a pair of hooks. Only used internally. 7294cf49a43SJulian Elischer */ 7304cf49a43SJulian Elischer static int 7314cf49a43SJulian Elischer ng_connect(hook_p hook1, hook_p hook2) 7324cf49a43SJulian Elischer { 7334cf49a43SJulian Elischer int error; 7344cf49a43SJulian Elischer 7354cf49a43SJulian Elischer hook1->peer = hook2; 7364cf49a43SJulian Elischer hook2->peer = hook1; 7374cf49a43SJulian Elischer 7384cf49a43SJulian Elischer /* Give each node the opportunity to veto the impending connection */ 7394cf49a43SJulian Elischer if (hook1->node->type->connect) { 7404cf49a43SJulian Elischer if ((error = (*hook1->node->type->connect) (hook1))) { 7414cf49a43SJulian Elischer ng_destroy_hook(hook1); /* also zaps hook2 */ 7424cf49a43SJulian Elischer return (error); 7434cf49a43SJulian Elischer } 7444cf49a43SJulian Elischer } 7454cf49a43SJulian Elischer if (hook2->node->type->connect) { 7464cf49a43SJulian Elischer if ((error = (*hook2->node->type->connect) (hook2))) { 7474cf49a43SJulian Elischer ng_destroy_hook(hook2); /* also zaps hook1 */ 7484cf49a43SJulian Elischer return (error); 7494cf49a43SJulian Elischer } 7504cf49a43SJulian Elischer } 7514cf49a43SJulian Elischer hook1->flags &= ~HK_INVALID; 7524cf49a43SJulian Elischer hook2->flags &= ~HK_INVALID; 7534cf49a43SJulian Elischer return (0); 7544cf49a43SJulian Elischer } 7554cf49a43SJulian Elischer 7564cf49a43SJulian Elischer /* 757899e9c4eSArchie Cobbs * Find a hook 758899e9c4eSArchie Cobbs * 759899e9c4eSArchie Cobbs * Node types may supply their own optimized routines for finding 760899e9c4eSArchie Cobbs * hooks. If none is supplied, we just do a linear search. 761899e9c4eSArchie Cobbs */ 762899e9c4eSArchie Cobbs hook_p 763899e9c4eSArchie Cobbs ng_findhook(node_p node, const char *name) 764899e9c4eSArchie Cobbs { 765899e9c4eSArchie Cobbs hook_p hook; 766899e9c4eSArchie Cobbs 767899e9c4eSArchie Cobbs if (node->type->findhook != NULL) 768899e9c4eSArchie Cobbs return (*node->type->findhook)(node, name); 769899e9c4eSArchie Cobbs LIST_FOREACH(hook, &node->hooks, hooks) { 770899e9c4eSArchie Cobbs if (hook->name != NULL && strcmp(hook->name, name) == 0) 771899e9c4eSArchie Cobbs return (hook); 772899e9c4eSArchie Cobbs } 773899e9c4eSArchie Cobbs return (NULL); 774899e9c4eSArchie Cobbs } 775899e9c4eSArchie Cobbs 776899e9c4eSArchie Cobbs /* 7774cf49a43SJulian Elischer * Destroy a hook 7784cf49a43SJulian Elischer * 7794cf49a43SJulian Elischer * As hooks are always attached, this really destroys two hooks. 7804cf49a43SJulian Elischer * The one given, and the one attached to it. Disconnect the hooks 7814cf49a43SJulian Elischer * from each other first. 7824cf49a43SJulian Elischer */ 7834cf49a43SJulian Elischer void 7844cf49a43SJulian Elischer ng_destroy_hook(hook_p hook) 7854cf49a43SJulian Elischer { 7864cf49a43SJulian Elischer hook_p peer = hook->peer; 7874cf49a43SJulian Elischer 7884cf49a43SJulian Elischer hook->flags |= HK_INVALID; /* as soon as possible */ 7894cf49a43SJulian Elischer if (peer) { 7904cf49a43SJulian Elischer peer->flags |= HK_INVALID; /* as soon as possible */ 7914cf49a43SJulian Elischer hook->peer = NULL; 7924cf49a43SJulian Elischer peer->peer = NULL; 7934cf49a43SJulian Elischer ng_disconnect_hook(peer); 7944cf49a43SJulian Elischer } 7954cf49a43SJulian Elischer ng_disconnect_hook(hook); 7964cf49a43SJulian Elischer } 7974cf49a43SJulian Elischer 7984cf49a43SJulian Elischer /* 7994cf49a43SJulian Elischer * Notify the node of the hook's demise. This may result in more actions 8004cf49a43SJulian Elischer * (e.g. shutdown) but we don't do that ourselves and don't know what 8014cf49a43SJulian Elischer * happens there. If there is no appropriate handler, then just remove it 8024cf49a43SJulian Elischer * (and decrement the reference count of it's node which in turn might 8034cf49a43SJulian Elischer * make something happen). 8044cf49a43SJulian Elischer */ 8054cf49a43SJulian Elischer static void 8064cf49a43SJulian Elischer ng_disconnect_hook(hook_p hook) 8074cf49a43SJulian Elischer { 8084cf49a43SJulian Elischer node_p node = hook->node; 8094cf49a43SJulian Elischer 8104cf49a43SJulian Elischer /* 8114cf49a43SJulian Elischer * Remove the hook from the node's list to avoid possible recursion 8124cf49a43SJulian Elischer * in case the disconnection results in node shutdown. 8134cf49a43SJulian Elischer */ 8144cf49a43SJulian Elischer LIST_REMOVE(hook, hooks); 8154cf49a43SJulian Elischer node->numhooks--; 8164cf49a43SJulian Elischer if (node->type->disconnect) { 8174cf49a43SJulian Elischer /* 8184cf49a43SJulian Elischer * The type handler may elect to destroy the peer so don't 8194cf49a43SJulian Elischer * trust its existance after this point. 8204cf49a43SJulian Elischer */ 8214cf49a43SJulian Elischer (*node->type->disconnect) (hook); 8224cf49a43SJulian Elischer } 8234cf49a43SJulian Elischer ng_unref(node); /* might be the last reference */ 8244cf49a43SJulian Elischer if (hook->name) 8254cf49a43SJulian Elischer FREE(hook->name, M_NETGRAPH); 8264cf49a43SJulian Elischer hook->node = NULL; /* may still be referenced elsewhere */ 8274cf49a43SJulian Elischer ng_unref_hook(hook); 8284cf49a43SJulian Elischer } 8294cf49a43SJulian Elischer 8304cf49a43SJulian Elischer /* 8314cf49a43SJulian Elischer * Take two hooks on a node and merge the connection so that the given node 8324cf49a43SJulian Elischer * is effectively bypassed. 8334cf49a43SJulian Elischer */ 8344cf49a43SJulian Elischer int 8354cf49a43SJulian Elischer ng_bypass(hook_p hook1, hook_p hook2) 8364cf49a43SJulian Elischer { 8374cf49a43SJulian Elischer if (hook1->node != hook2->node) 8384cf49a43SJulian Elischer return (EINVAL); 8394cf49a43SJulian Elischer hook1->peer->peer = hook2->peer; 8404cf49a43SJulian Elischer hook2->peer->peer = hook1->peer; 8414cf49a43SJulian Elischer 8424cf49a43SJulian Elischer /* XXX If we ever cache methods on hooks update them as well */ 8434cf49a43SJulian Elischer hook1->peer = NULL; 8444cf49a43SJulian Elischer hook2->peer = NULL; 8454cf49a43SJulian Elischer ng_destroy_hook(hook1); 8464cf49a43SJulian Elischer ng_destroy_hook(hook2); 8474cf49a43SJulian Elischer return (0); 8484cf49a43SJulian Elischer } 8494cf49a43SJulian Elischer 8504cf49a43SJulian Elischer /* 8514cf49a43SJulian Elischer * Install a new netgraph type 8524cf49a43SJulian Elischer */ 8534cf49a43SJulian Elischer int 8544cf49a43SJulian Elischer ng_newtype(struct ng_type *tp) 8554cf49a43SJulian Elischer { 8564cf49a43SJulian Elischer const size_t namelen = strlen(tp->name); 8574cf49a43SJulian Elischer 8584cf49a43SJulian Elischer /* Check version and type name fields */ 8594cf49a43SJulian Elischer if (tp->version != NG_VERSION || namelen == 0 || namelen > NG_TYPELEN) { 8604cf49a43SJulian Elischer TRAP_ERROR; 8614cf49a43SJulian Elischer return (EINVAL); 8624cf49a43SJulian Elischer } 8634cf49a43SJulian Elischer 8644cf49a43SJulian Elischer /* Check for name collision */ 8654cf49a43SJulian Elischer if (ng_findtype(tp->name) != NULL) { 8664cf49a43SJulian Elischer TRAP_ERROR; 8674cf49a43SJulian Elischer return (EEXIST); 8684cf49a43SJulian Elischer } 8694cf49a43SJulian Elischer 8704cf49a43SJulian Elischer /* Link in new type */ 8714cf49a43SJulian Elischer LIST_INSERT_HEAD(&typelist, tp, types); 8724cf49a43SJulian Elischer tp->refs = 0; 8734cf49a43SJulian Elischer return (0); 8744cf49a43SJulian Elischer } 8754cf49a43SJulian Elischer 8764cf49a43SJulian Elischer /* 8774cf49a43SJulian Elischer * Look for a type of the name given 8784cf49a43SJulian Elischer */ 8794cf49a43SJulian Elischer struct ng_type * 8804cf49a43SJulian Elischer ng_findtype(const char *typename) 8814cf49a43SJulian Elischer { 8824cf49a43SJulian Elischer struct ng_type *type; 8834cf49a43SJulian Elischer 8844cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) { 8854cf49a43SJulian Elischer if (strcmp(type->name, typename) == 0) 8864cf49a43SJulian Elischer break; 8874cf49a43SJulian Elischer } 8884cf49a43SJulian Elischer return (type); 8894cf49a43SJulian Elischer } 8904cf49a43SJulian Elischer 8914cf49a43SJulian Elischer 8924cf49a43SJulian Elischer /************************************************************************ 8934cf49a43SJulian Elischer Composite routines 8944cf49a43SJulian Elischer ************************************************************************/ 8954cf49a43SJulian Elischer 8964cf49a43SJulian Elischer /* 8974cf49a43SJulian Elischer * Make a peer and connect. The order is arranged to minimise 8984cf49a43SJulian Elischer * the work needed to back out in case of error. 8994cf49a43SJulian Elischer */ 9004cf49a43SJulian Elischer int 9014cf49a43SJulian Elischer ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 9024cf49a43SJulian Elischer { 9034cf49a43SJulian Elischer node_p node2; 9044cf49a43SJulian Elischer hook_p hook; 9054cf49a43SJulian Elischer hook_p hook2; 9064cf49a43SJulian Elischer int error; 9074cf49a43SJulian Elischer 9084cf49a43SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) 9094cf49a43SJulian Elischer return (error); 9104cf49a43SJulian Elischer if ((error = ng_make_node(type, &node2))) { 9114cf49a43SJulian Elischer ng_destroy_hook(hook); 9124cf49a43SJulian Elischer return (error); 9134cf49a43SJulian Elischer } 9144cf49a43SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 9154cf49a43SJulian Elischer ng_rmnode(node2); 9164cf49a43SJulian Elischer ng_destroy_hook(hook); 9174cf49a43SJulian Elischer return (error); 9184cf49a43SJulian Elischer } 9194cf49a43SJulian Elischer 9204cf49a43SJulian Elischer /* 9214cf49a43SJulian Elischer * Actually link the two hooks together.. on failure they are 9224cf49a43SJulian Elischer * destroyed so we don't have to do that here. 9234cf49a43SJulian Elischer */ 9244cf49a43SJulian Elischer if ((error = ng_connect(hook, hook2))) 9254cf49a43SJulian Elischer ng_rmnode(node2); 9264cf49a43SJulian Elischer return (error); 9274cf49a43SJulian Elischer } 9284cf49a43SJulian Elischer 9294cf49a43SJulian Elischer /* 9304cf49a43SJulian Elischer * Connect two nodes using the specified hooks 9314cf49a43SJulian Elischer */ 9324cf49a43SJulian Elischer int 9334cf49a43SJulian Elischer ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2) 9344cf49a43SJulian Elischer { 9354cf49a43SJulian Elischer int error; 9364cf49a43SJulian Elischer hook_p hook; 9374cf49a43SJulian Elischer hook_p hook2; 9384cf49a43SJulian Elischer 9394cf49a43SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) 9404cf49a43SJulian Elischer return (error); 9414cf49a43SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 9424cf49a43SJulian Elischer ng_destroy_hook(hook); 9434cf49a43SJulian Elischer return (error); 9444cf49a43SJulian Elischer } 9454cf49a43SJulian Elischer return (ng_connect(hook, hook2)); 9464cf49a43SJulian Elischer } 9474cf49a43SJulian Elischer 9484cf49a43SJulian Elischer /* 9494cf49a43SJulian Elischer * Parse and verify a string of the form: <NODE:><PATH> 9504cf49a43SJulian Elischer * 9514cf49a43SJulian Elischer * Such a string can refer to a specific node or a specific hook 9524cf49a43SJulian Elischer * on a specific node, depending on how you look at it. In the 9534cf49a43SJulian Elischer * latter case, the PATH component must not end in a dot. 9544cf49a43SJulian Elischer * 9554cf49a43SJulian Elischer * Both <NODE:> and <PATH> are optional. The <PATH> is a string 9564cf49a43SJulian Elischer * of hook names separated by dots. This breaks out the original 9574cf49a43SJulian Elischer * string, setting *nodep to "NODE" (or NULL if none) and *pathp 9584cf49a43SJulian Elischer * to "PATH" (or NULL if degenerate). Also, *hookp will point to 9594cf49a43SJulian Elischer * the final hook component of <PATH>, if any, otherwise NULL. 9604cf49a43SJulian Elischer * 9614cf49a43SJulian Elischer * This returns -1 if the path is malformed. The char ** are optional. 9624cf49a43SJulian Elischer */ 9634cf49a43SJulian Elischer 9644cf49a43SJulian Elischer int 9654cf49a43SJulian Elischer ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 9664cf49a43SJulian Elischer { 9674cf49a43SJulian Elischer char *node, *path, *hook; 9684cf49a43SJulian Elischer int k; 9694cf49a43SJulian Elischer 9704cf49a43SJulian Elischer /* 9714cf49a43SJulian Elischer * Extract absolute NODE, if any 9724cf49a43SJulian Elischer */ 9734cf49a43SJulian Elischer for (path = addr; *path && *path != ':'; path++); 9744cf49a43SJulian Elischer if (*path) { 9754cf49a43SJulian Elischer node = addr; /* Here's the NODE */ 9764cf49a43SJulian Elischer *path++ = '\0'; /* Here's the PATH */ 9774cf49a43SJulian Elischer 9784cf49a43SJulian Elischer /* Node name must not be empty */ 9794cf49a43SJulian Elischer if (!*node) 9804cf49a43SJulian Elischer return -1; 9814cf49a43SJulian Elischer 9824cf49a43SJulian Elischer /* A name of "." is OK; otherwise '.' not allowed */ 9834cf49a43SJulian Elischer if (strcmp(node, ".") != 0) { 9844cf49a43SJulian Elischer for (k = 0; node[k]; k++) 9854cf49a43SJulian Elischer if (node[k] == '.') 9864cf49a43SJulian Elischer return -1; 9874cf49a43SJulian Elischer } 9884cf49a43SJulian Elischer } else { 9894cf49a43SJulian Elischer node = NULL; /* No absolute NODE */ 9904cf49a43SJulian Elischer path = addr; /* Here's the PATH */ 9914cf49a43SJulian Elischer } 9924cf49a43SJulian Elischer 9934cf49a43SJulian Elischer /* Snoop for illegal characters in PATH */ 9944cf49a43SJulian Elischer for (k = 0; path[k]; k++) 9954cf49a43SJulian Elischer if (path[k] == ':') 9964cf49a43SJulian Elischer return -1; 9974cf49a43SJulian Elischer 9984cf49a43SJulian Elischer /* Check for no repeated dots in PATH */ 9994cf49a43SJulian Elischer for (k = 0; path[k]; k++) 10004cf49a43SJulian Elischer if (path[k] == '.' && path[k + 1] == '.') 10014cf49a43SJulian Elischer return -1; 10024cf49a43SJulian Elischer 10034cf49a43SJulian Elischer /* Remove extra (degenerate) dots from beginning or end of PATH */ 10044cf49a43SJulian Elischer if (path[0] == '.') 10054cf49a43SJulian Elischer path++; 10064cf49a43SJulian Elischer if (*path && path[strlen(path) - 1] == '.') 10074cf49a43SJulian Elischer path[strlen(path) - 1] = 0; 10084cf49a43SJulian Elischer 10094cf49a43SJulian Elischer /* If PATH has a dot, then we're not talking about a hook */ 10104cf49a43SJulian Elischer if (*path) { 10114cf49a43SJulian Elischer for (hook = path, k = 0; path[k]; k++) 10124cf49a43SJulian Elischer if (path[k] == '.') { 10134cf49a43SJulian Elischer hook = NULL; 10144cf49a43SJulian Elischer break; 10154cf49a43SJulian Elischer } 10164cf49a43SJulian Elischer } else 10174cf49a43SJulian Elischer path = hook = NULL; 10184cf49a43SJulian Elischer 10194cf49a43SJulian Elischer /* Done */ 10204cf49a43SJulian Elischer if (nodep) 10214cf49a43SJulian Elischer *nodep = node; 10224cf49a43SJulian Elischer if (pathp) 10234cf49a43SJulian Elischer *pathp = path; 10244cf49a43SJulian Elischer if (hookp) 10254cf49a43SJulian Elischer *hookp = hook; 10264cf49a43SJulian Elischer return (0); 10274cf49a43SJulian Elischer } 10284cf49a43SJulian Elischer 10294cf49a43SJulian Elischer /* 10304cf49a43SJulian Elischer * Given a path, which may be absolute or relative, and a starting node, 10314cf49a43SJulian Elischer * return the destination node. Compute the "return address" if desired. 10324cf49a43SJulian Elischer */ 10334cf49a43SJulian Elischer int 1034859a4d16SJulian Elischer ng_path2node(node_p here, const char *address, node_p *destp, hook_p *lasthook) 10354cf49a43SJulian Elischer { 10364cf49a43SJulian Elischer char fullpath[NG_PATHLEN + 1]; 10374cf49a43SJulian Elischer char *nodename, *path, pbuf[2]; 10384cf49a43SJulian Elischer node_p node; 10394cf49a43SJulian Elischer char *cp; 1040a4ec03cfSJulian Elischer hook_p hook = NULL; 10414cf49a43SJulian Elischer 10424cf49a43SJulian Elischer /* Initialize */ 10434cf49a43SJulian Elischer if (destp == NULL) 10444cf49a43SJulian Elischer return EINVAL; 10454cf49a43SJulian Elischer *destp = NULL; 10464cf49a43SJulian Elischer 10474cf49a43SJulian Elischer /* Make a writable copy of address for ng_path_parse() */ 10484cf49a43SJulian Elischer strncpy(fullpath, address, sizeof(fullpath) - 1); 10494cf49a43SJulian Elischer fullpath[sizeof(fullpath) - 1] = '\0'; 10504cf49a43SJulian Elischer 10514cf49a43SJulian Elischer /* Parse out node and sequence of hooks */ 10524cf49a43SJulian Elischer if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 10534cf49a43SJulian Elischer TRAP_ERROR; 10544cf49a43SJulian Elischer return EINVAL; 10554cf49a43SJulian Elischer } 10564cf49a43SJulian Elischer if (path == NULL) { 10574cf49a43SJulian Elischer pbuf[0] = '.'; /* Needs to be writable */ 10584cf49a43SJulian Elischer pbuf[1] = '\0'; 10594cf49a43SJulian Elischer path = pbuf; 10604cf49a43SJulian Elischer } 10614cf49a43SJulian Elischer 10624cf49a43SJulian Elischer /* For an absolute address, jump to the starting node */ 10634cf49a43SJulian Elischer if (nodename) { 10644cf49a43SJulian Elischer node = ng_findname(here, nodename); 10654cf49a43SJulian Elischer if (node == NULL) { 10664cf49a43SJulian Elischer TRAP_ERROR; 10674cf49a43SJulian Elischer return (ENOENT); 10684cf49a43SJulian Elischer } 10694cf49a43SJulian Elischer } else 10704cf49a43SJulian Elischer node = here; 10714cf49a43SJulian Elischer 10724cf49a43SJulian Elischer /* Now follow the sequence of hooks */ 10734cf49a43SJulian Elischer for (cp = path; node != NULL && *cp != '\0'; ) { 10744cf49a43SJulian Elischer char *segment; 10754cf49a43SJulian Elischer 10764cf49a43SJulian Elischer /* 10774cf49a43SJulian Elischer * Break out the next path segment. Replace the dot we just 10784cf49a43SJulian Elischer * found with a NUL; "cp" points to the next segment (or the 10794cf49a43SJulian Elischer * NUL at the end). 10804cf49a43SJulian Elischer */ 10814cf49a43SJulian Elischer for (segment = cp; *cp != '\0'; cp++) { 10824cf49a43SJulian Elischer if (*cp == '.') { 10834cf49a43SJulian Elischer *cp++ = '\0'; 10844cf49a43SJulian Elischer break; 10854cf49a43SJulian Elischer } 10864cf49a43SJulian Elischer } 10874cf49a43SJulian Elischer 10884cf49a43SJulian Elischer /* Empty segment */ 10894cf49a43SJulian Elischer if (*segment == '\0') 10904cf49a43SJulian Elischer continue; 10914cf49a43SJulian Elischer 10924cf49a43SJulian Elischer /* We have a segment, so look for a hook by that name */ 1093899e9c4eSArchie Cobbs hook = ng_findhook(node, segment); 10944cf49a43SJulian Elischer 10954cf49a43SJulian Elischer /* Can't get there from here... */ 10964cf49a43SJulian Elischer if (hook == NULL 10974cf49a43SJulian Elischer || hook->peer == NULL 10984cf49a43SJulian Elischer || (hook->flags & HK_INVALID) != 0) { 10994cf49a43SJulian Elischer TRAP_ERROR; 11004cf49a43SJulian Elischer return (ENOENT); 11014cf49a43SJulian Elischer } 11024cf49a43SJulian Elischer 11034cf49a43SJulian Elischer /* Hop on over to the next node */ 11044cf49a43SJulian Elischer node = hook->peer->node; 11054cf49a43SJulian Elischer } 11064cf49a43SJulian Elischer 11074cf49a43SJulian Elischer /* If node somehow missing, fail here (probably this is not needed) */ 11084cf49a43SJulian Elischer if (node == NULL) { 11094cf49a43SJulian Elischer TRAP_ERROR; 11104cf49a43SJulian Elischer return (ENXIO); 11114cf49a43SJulian Elischer } 11124cf49a43SJulian Elischer 11134cf49a43SJulian Elischer /* Done */ 11144cf49a43SJulian Elischer *destp = node; 11151bdebe4dSArchie Cobbs if (lasthook != NULL) 11161bdebe4dSArchie Cobbs *lasthook = hook ? hook->peer : NULL; 11174cf49a43SJulian Elischer return (0); 11184cf49a43SJulian Elischer } 11194cf49a43SJulian Elischer 11204cf49a43SJulian Elischer /* 11214cf49a43SJulian Elischer * Call the appropriate message handler for the object. 11224cf49a43SJulian Elischer * It is up to the message handler to free the message. 11234cf49a43SJulian Elischer * If it's a generic message, handle it generically, otherwise 11244cf49a43SJulian Elischer * call the type's message handler (if it exists) 1125e8a49db2SJulian Elischer * XXX (race). Remember that a queued message may reference a node 1126e8a49db2SJulian Elischer * or hook that has just been invalidated. It will exist 1127e8a49db2SJulian Elischer * as the queue code is holding a reference, but.. 11284cf49a43SJulian Elischer */ 11294cf49a43SJulian Elischer 1130a4ec03cfSJulian Elischer #define CALL_MSG_HANDLER(error, node, msg, retaddr, resp, hook) \ 11314cf49a43SJulian Elischer do { \ 11324cf49a43SJulian Elischer if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \ 11334cf49a43SJulian Elischer (error) = ng_generic_msg((node), (msg), \ 1134a4ec03cfSJulian Elischer (retaddr), (resp), (hook)); \ 11354cf49a43SJulian Elischer } else { \ 11364cf49a43SJulian Elischer if ((node)->type->rcvmsg != NULL) { \ 11374cf49a43SJulian Elischer (error) = (*(node)->type->rcvmsg)((node), \ 1138a4ec03cfSJulian Elischer (msg), (retaddr), (resp), (hook)); \ 11394cf49a43SJulian Elischer } else { \ 11404cf49a43SJulian Elischer TRAP_ERROR; \ 11414cf49a43SJulian Elischer FREE((msg), M_NETGRAPH); \ 11424cf49a43SJulian Elischer (error) = EINVAL; \ 11434cf49a43SJulian Elischer } \ 11444cf49a43SJulian Elischer } \ 11454cf49a43SJulian Elischer } while (0) 11464cf49a43SJulian Elischer 11474cf49a43SJulian Elischer 11484cf49a43SJulian Elischer /* 1149859a4d16SJulian Elischer * Send a control message to a node. 1150859a4d16SJulian Elischer * If hook is supplied, use it in preference to the address. 1151859a4d16SJulian Elischer * If the return address is not supplied it will be set to this node. 11524cf49a43SJulian Elischer */ 11534cf49a43SJulian Elischer int 11544cf49a43SJulian Elischer ng_send_msg(node_p here, struct ng_mesg *msg, const char *address, 1155859a4d16SJulian Elischer hook_p hook, char *retaddr, struct ng_mesg **rptr) 11564cf49a43SJulian Elischer { 11574cf49a43SJulian Elischer node_p dest = NULL; 11584cf49a43SJulian Elischer int error; 1159a4ec03cfSJulian Elischer hook_p lasthook; 11604cf49a43SJulian Elischer 1161859a4d16SJulian Elischer /* 1162859a4d16SJulian Elischer * Find the target node. 1163859a4d16SJulian Elischer * If there is a HOOK argument, then use that in preference 1164859a4d16SJulian Elischer * to the address. 1165859a4d16SJulian Elischer */ 1166859a4d16SJulian Elischer if (hook) { 1167859a4d16SJulian Elischer lasthook = hook->peer; 1168859a4d16SJulian Elischer dest = lasthook->node; 1169859a4d16SJulian Elischer } else { 1170859a4d16SJulian Elischer error = ng_path2node(here, address, &dest, &lasthook); 11714cf49a43SJulian Elischer if (error) { 11724cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 1173859a4d16SJulian Elischer return (error); 1174859a4d16SJulian Elischer } 1175859a4d16SJulian Elischer } 1176859a4d16SJulian Elischer 1177859a4d16SJulian Elischer /* If the user didn't supply a return addres, assume it's "here". */ 1178859a4d16SJulian Elischer if (retaddr == NULL) { 1179859a4d16SJulian Elischer /* 1180859a4d16SJulian Elischer * Now fill out the return address, 1181859a4d16SJulian Elischer * i.e. the name/ID of the sender. (If we didn't get one) 1182859a4d16SJulian Elischer */ 1183859a4d16SJulian Elischer MALLOC(retaddr, char *, NG_NODELEN + 2, M_NETGRAPH, M_NOWAIT); 1184859a4d16SJulian Elischer if (retaddr == NULL) { 1185859a4d16SJulian Elischer TRAP_ERROR; 1186859a4d16SJulian Elischer return (ENOMEM); 1187859a4d16SJulian Elischer } 1188859a4d16SJulian Elischer if (here->name != NULL) 1189859a4d16SJulian Elischer sprintf(retaddr, "%s:", here->name); 1190859a4d16SJulian Elischer else 1191859a4d16SJulian Elischer sprintf(retaddr, "[%x]:", ng_node2ID(here)); 11924cf49a43SJulian Elischer } 11934cf49a43SJulian Elischer 11944cf49a43SJulian Elischer /* Make sure the resp field is null before we start */ 11954cf49a43SJulian Elischer if (rptr != NULL) 11964cf49a43SJulian Elischer *rptr = NULL; 11974cf49a43SJulian Elischer 1198a4ec03cfSJulian Elischer CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr, lasthook); 11994cf49a43SJulian Elischer 12004cf49a43SJulian Elischer /* Make sure that if there is a response, it has the RESP bit set */ 12014cf49a43SJulian Elischer if ((error == 0) && rptr && *rptr) 12024cf49a43SJulian Elischer (*rptr)->header.flags |= NGF_RESP; 12034cf49a43SJulian Elischer 12044cf49a43SJulian Elischer /* 12054cf49a43SJulian Elischer * If we had a return address it is up to us to free it. They should 12064cf49a43SJulian Elischer * have taken a copy if they needed to make a delayed response. 12074cf49a43SJulian Elischer */ 12084cf49a43SJulian Elischer if (retaddr) 12094cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 12104cf49a43SJulian Elischer return (error); 12114cf49a43SJulian Elischer } 12124cf49a43SJulian Elischer 12134cf49a43SJulian Elischer /* 12144cf49a43SJulian Elischer * Implement the 'generic' control messages 12154cf49a43SJulian Elischer */ 12164cf49a43SJulian Elischer static int 12174cf49a43SJulian Elischer ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr, 1218a4ec03cfSJulian Elischer struct ng_mesg **resp, hook_p lasthook) 12194cf49a43SJulian Elischer { 12204cf49a43SJulian Elischer int error = 0; 12214cf49a43SJulian Elischer 12224cf49a43SJulian Elischer if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 12234cf49a43SJulian Elischer TRAP_ERROR; 12244cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 12254cf49a43SJulian Elischer return (EINVAL); 12264cf49a43SJulian Elischer } 12274cf49a43SJulian Elischer switch (msg->header.cmd) { 12284cf49a43SJulian Elischer case NGM_SHUTDOWN: 12294cf49a43SJulian Elischer ng_rmnode(here); 12304cf49a43SJulian Elischer break; 12314cf49a43SJulian Elischer case NGM_MKPEER: 12324cf49a43SJulian Elischer { 12334cf49a43SJulian Elischer struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 12344cf49a43SJulian Elischer 12354cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*mkp)) { 12364cf49a43SJulian Elischer TRAP_ERROR; 12374cf49a43SJulian Elischer return (EINVAL); 12384cf49a43SJulian Elischer } 12394cf49a43SJulian Elischer mkp->type[sizeof(mkp->type) - 1] = '\0'; 12404cf49a43SJulian Elischer mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 12414cf49a43SJulian Elischer mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 12424cf49a43SJulian Elischer error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 12434cf49a43SJulian Elischer break; 12444cf49a43SJulian Elischer } 12454cf49a43SJulian Elischer case NGM_CONNECT: 12464cf49a43SJulian Elischer { 12474cf49a43SJulian Elischer struct ngm_connect *const con = 12484cf49a43SJulian Elischer (struct ngm_connect *) msg->data; 12494cf49a43SJulian Elischer node_p node2; 12504cf49a43SJulian Elischer 12514cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*con)) { 12524cf49a43SJulian Elischer TRAP_ERROR; 12534cf49a43SJulian Elischer return (EINVAL); 12544cf49a43SJulian Elischer } 12554cf49a43SJulian Elischer con->path[sizeof(con->path) - 1] = '\0'; 12564cf49a43SJulian Elischer con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 12574cf49a43SJulian Elischer con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 1258859a4d16SJulian Elischer error = ng_path2node(here, con->path, &node2, NULL); 12594cf49a43SJulian Elischer if (error) 12604cf49a43SJulian Elischer break; 12614cf49a43SJulian Elischer error = ng_con_nodes(here, con->ourhook, node2, con->peerhook); 12624cf49a43SJulian Elischer break; 12634cf49a43SJulian Elischer } 12644cf49a43SJulian Elischer case NGM_NAME: 12654cf49a43SJulian Elischer { 12664cf49a43SJulian Elischer struct ngm_name *const nam = (struct ngm_name *) msg->data; 12674cf49a43SJulian Elischer 12684cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*nam)) { 12694cf49a43SJulian Elischer TRAP_ERROR; 12704cf49a43SJulian Elischer return (EINVAL); 12714cf49a43SJulian Elischer } 12724cf49a43SJulian Elischer nam->name[sizeof(nam->name) - 1] = '\0'; 12734cf49a43SJulian Elischer error = ng_name_node(here, nam->name); 12744cf49a43SJulian Elischer break; 12754cf49a43SJulian Elischer } 12764cf49a43SJulian Elischer case NGM_RMHOOK: 12774cf49a43SJulian Elischer { 12784cf49a43SJulian Elischer struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 12794cf49a43SJulian Elischer hook_p hook; 12804cf49a43SJulian Elischer 12814cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*rmh)) { 12824cf49a43SJulian Elischer TRAP_ERROR; 12834cf49a43SJulian Elischer return (EINVAL); 12844cf49a43SJulian Elischer } 12854cf49a43SJulian Elischer rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 1286899e9c4eSArchie Cobbs if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 12874cf49a43SJulian Elischer ng_destroy_hook(hook); 12884cf49a43SJulian Elischer break; 12894cf49a43SJulian Elischer } 12904cf49a43SJulian Elischer case NGM_NODEINFO: 12914cf49a43SJulian Elischer { 12924cf49a43SJulian Elischer struct nodeinfo *ni; 12934cf49a43SJulian Elischer struct ng_mesg *rp; 12944cf49a43SJulian Elischer 12954cf49a43SJulian Elischer /* Get response struct */ 12964cf49a43SJulian Elischer if (resp == NULL) { 12974cf49a43SJulian Elischer error = EINVAL; 12984cf49a43SJulian Elischer break; 12994cf49a43SJulian Elischer } 13004cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT); 13014cf49a43SJulian Elischer if (rp == NULL) { 13024cf49a43SJulian Elischer error = ENOMEM; 13034cf49a43SJulian Elischer break; 13044cf49a43SJulian Elischer } 13054cf49a43SJulian Elischer 13064cf49a43SJulian Elischer /* Fill in node info */ 13074cf49a43SJulian Elischer ni = (struct nodeinfo *) rp->data; 13084cf49a43SJulian Elischer if (here->name != NULL) 13094cf49a43SJulian Elischer strncpy(ni->name, here->name, NG_NODELEN); 13104cf49a43SJulian Elischer strncpy(ni->type, here->type->name, NG_TYPELEN); 1311dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 13124cf49a43SJulian Elischer ni->hooks = here->numhooks; 13134cf49a43SJulian Elischer *resp = rp; 13144cf49a43SJulian Elischer break; 13154cf49a43SJulian Elischer } 13164cf49a43SJulian Elischer case NGM_LISTHOOKS: 13174cf49a43SJulian Elischer { 13184cf49a43SJulian Elischer const int nhooks = here->numhooks; 13194cf49a43SJulian Elischer struct hooklist *hl; 13204cf49a43SJulian Elischer struct nodeinfo *ni; 13214cf49a43SJulian Elischer struct ng_mesg *rp; 13224cf49a43SJulian Elischer hook_p hook; 13234cf49a43SJulian Elischer 13244cf49a43SJulian Elischer /* Get response struct */ 13254cf49a43SJulian Elischer if (resp == NULL) { 13264cf49a43SJulian Elischer error = EINVAL; 13274cf49a43SJulian Elischer break; 13284cf49a43SJulian Elischer } 13294cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*hl) 13304cf49a43SJulian Elischer + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 13314cf49a43SJulian Elischer if (rp == NULL) { 13324cf49a43SJulian Elischer error = ENOMEM; 13334cf49a43SJulian Elischer break; 13344cf49a43SJulian Elischer } 13354cf49a43SJulian Elischer hl = (struct hooklist *) rp->data; 13364cf49a43SJulian Elischer ni = &hl->nodeinfo; 13374cf49a43SJulian Elischer 13384cf49a43SJulian Elischer /* Fill in node info */ 13394cf49a43SJulian Elischer if (here->name) 13404cf49a43SJulian Elischer strncpy(ni->name, here->name, NG_NODELEN); 13414cf49a43SJulian Elischer strncpy(ni->type, here->type->name, NG_TYPELEN); 1342dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 13434cf49a43SJulian Elischer 13444cf49a43SJulian Elischer /* Cycle through the linked list of hooks */ 13454cf49a43SJulian Elischer ni->hooks = 0; 13464cf49a43SJulian Elischer LIST_FOREACH(hook, &here->hooks, hooks) { 13474cf49a43SJulian Elischer struct linkinfo *const link = &hl->link[ni->hooks]; 13484cf49a43SJulian Elischer 13494cf49a43SJulian Elischer if (ni->hooks >= nhooks) { 13504cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 13514cf49a43SJulian Elischer __FUNCTION__, "hooks"); 13524cf49a43SJulian Elischer break; 13534cf49a43SJulian Elischer } 13544cf49a43SJulian Elischer if ((hook->flags & HK_INVALID) != 0) 13554cf49a43SJulian Elischer continue; 13564cf49a43SJulian Elischer strncpy(link->ourhook, hook->name, NG_HOOKLEN); 13574cf49a43SJulian Elischer strncpy(link->peerhook, hook->peer->name, NG_HOOKLEN); 13584cf49a43SJulian Elischer if (hook->peer->node->name != NULL) 13594cf49a43SJulian Elischer strncpy(link->nodeinfo.name, 13604cf49a43SJulian Elischer hook->peer->node->name, NG_NODELEN); 13614cf49a43SJulian Elischer strncpy(link->nodeinfo.type, 13624cf49a43SJulian Elischer hook->peer->node->type->name, NG_TYPELEN); 1363dc90cad9SJulian Elischer link->nodeinfo.id = ng_node2ID(hook->peer->node); 13644cf49a43SJulian Elischer link->nodeinfo.hooks = hook->peer->node->numhooks; 13654cf49a43SJulian Elischer ni->hooks++; 13664cf49a43SJulian Elischer } 13674cf49a43SJulian Elischer *resp = rp; 13684cf49a43SJulian Elischer break; 13694cf49a43SJulian Elischer } 13704cf49a43SJulian Elischer 13714cf49a43SJulian Elischer case NGM_LISTNAMES: 13724cf49a43SJulian Elischer case NGM_LISTNODES: 13734cf49a43SJulian Elischer { 13744cf49a43SJulian Elischer const int unnamed = (msg->header.cmd == NGM_LISTNODES); 13754cf49a43SJulian Elischer struct namelist *nl; 13764cf49a43SJulian Elischer struct ng_mesg *rp; 13774cf49a43SJulian Elischer node_p node; 13784cf49a43SJulian Elischer int num = 0; 13794cf49a43SJulian Elischer 13804cf49a43SJulian Elischer if (resp == NULL) { 13814cf49a43SJulian Elischer error = EINVAL; 13824cf49a43SJulian Elischer break; 13834cf49a43SJulian Elischer } 13844cf49a43SJulian Elischer 13854cf49a43SJulian Elischer /* Count number of nodes */ 13864cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 13874cf49a43SJulian Elischer if (unnamed || node->name != NULL) 13884cf49a43SJulian Elischer num++; 13894cf49a43SJulian Elischer } 13904cf49a43SJulian Elischer 13914cf49a43SJulian Elischer /* Get response struct */ 13924cf49a43SJulian Elischer if (resp == NULL) { 13934cf49a43SJulian Elischer error = EINVAL; 13944cf49a43SJulian Elischer break; 13954cf49a43SJulian Elischer } 13964cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*nl) 13974cf49a43SJulian Elischer + (num * sizeof(struct nodeinfo)), M_NOWAIT); 13984cf49a43SJulian Elischer if (rp == NULL) { 13994cf49a43SJulian Elischer error = ENOMEM; 14004cf49a43SJulian Elischer break; 14014cf49a43SJulian Elischer } 14024cf49a43SJulian Elischer nl = (struct namelist *) rp->data; 14034cf49a43SJulian Elischer 14044cf49a43SJulian Elischer /* Cycle through the linked list of nodes */ 14054cf49a43SJulian Elischer nl->numnames = 0; 14064cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 14074cf49a43SJulian Elischer struct nodeinfo *const np = &nl->nodeinfo[nl->numnames]; 14084cf49a43SJulian Elischer 14094cf49a43SJulian Elischer if (nl->numnames >= num) { 14104cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 14114cf49a43SJulian Elischer __FUNCTION__, "nodes"); 14124cf49a43SJulian Elischer break; 14134cf49a43SJulian Elischer } 14144cf49a43SJulian Elischer if ((node->flags & NG_INVALID) != 0) 14154cf49a43SJulian Elischer continue; 14164cf49a43SJulian Elischer if (!unnamed && node->name == NULL) 14174cf49a43SJulian Elischer continue; 14184cf49a43SJulian Elischer if (node->name != NULL) 14194cf49a43SJulian Elischer strncpy(np->name, node->name, NG_NODELEN); 14204cf49a43SJulian Elischer strncpy(np->type, node->type->name, NG_TYPELEN); 1421dc90cad9SJulian Elischer np->id = ng_node2ID(node); 14224cf49a43SJulian Elischer np->hooks = node->numhooks; 14234cf49a43SJulian Elischer nl->numnames++; 14244cf49a43SJulian Elischer } 14254cf49a43SJulian Elischer *resp = rp; 14264cf49a43SJulian Elischer break; 14274cf49a43SJulian Elischer } 14284cf49a43SJulian Elischer 14294cf49a43SJulian Elischer case NGM_LISTTYPES: 14304cf49a43SJulian Elischer { 14314cf49a43SJulian Elischer struct typelist *tl; 14324cf49a43SJulian Elischer struct ng_mesg *rp; 14334cf49a43SJulian Elischer struct ng_type *type; 14344cf49a43SJulian Elischer int num = 0; 14354cf49a43SJulian Elischer 14364cf49a43SJulian Elischer if (resp == NULL) { 14374cf49a43SJulian Elischer error = EINVAL; 14384cf49a43SJulian Elischer break; 14394cf49a43SJulian Elischer } 14404cf49a43SJulian Elischer 14414cf49a43SJulian Elischer /* Count number of types */ 14424cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) 14434cf49a43SJulian Elischer num++; 14444cf49a43SJulian Elischer 14454cf49a43SJulian Elischer /* Get response struct */ 14464cf49a43SJulian Elischer if (resp == NULL) { 14474cf49a43SJulian Elischer error = EINVAL; 14484cf49a43SJulian Elischer break; 14494cf49a43SJulian Elischer } 14504cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*tl) 14514cf49a43SJulian Elischer + (num * sizeof(struct typeinfo)), M_NOWAIT); 14524cf49a43SJulian Elischer if (rp == NULL) { 14534cf49a43SJulian Elischer error = ENOMEM; 14544cf49a43SJulian Elischer break; 14554cf49a43SJulian Elischer } 14564cf49a43SJulian Elischer tl = (struct typelist *) rp->data; 14574cf49a43SJulian Elischer 14584cf49a43SJulian Elischer /* Cycle through the linked list of types */ 14594cf49a43SJulian Elischer tl->numtypes = 0; 14604cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) { 14614cf49a43SJulian Elischer struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 14624cf49a43SJulian Elischer 14634cf49a43SJulian Elischer if (tl->numtypes >= num) { 14644cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 14654cf49a43SJulian Elischer __FUNCTION__, "types"); 14664cf49a43SJulian Elischer break; 14674cf49a43SJulian Elischer } 1468a096e45aSArchie Cobbs strncpy(tp->type_name, type->name, NG_TYPELEN); 14694cf49a43SJulian Elischer tp->numnodes = type->refs; 14704cf49a43SJulian Elischer tl->numtypes++; 14714cf49a43SJulian Elischer } 14724cf49a43SJulian Elischer *resp = rp; 14734cf49a43SJulian Elischer break; 14744cf49a43SJulian Elischer } 14754cf49a43SJulian Elischer 1476f8307e12SArchie Cobbs case NGM_BINARY2ASCII: 1477f8307e12SArchie Cobbs { 14787133ac27SArchie Cobbs int bufSize = 20 * 1024; /* XXX hard coded constant */ 1479f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 1480f8307e12SArchie Cobbs const struct ng_cmdlist *c; 1481f8307e12SArchie Cobbs struct ng_mesg *rp, *binary, *ascii; 1482f8307e12SArchie Cobbs 1483f8307e12SArchie Cobbs /* Data area must contain a valid netgraph message */ 1484f8307e12SArchie Cobbs binary = (struct ng_mesg *)msg->data; 1485f8307e12SArchie Cobbs if (msg->header.arglen < sizeof(struct ng_mesg) 1486f8307e12SArchie Cobbs || msg->header.arglen - sizeof(struct ng_mesg) 1487f8307e12SArchie Cobbs < binary->header.arglen) { 1488f8307e12SArchie Cobbs error = EINVAL; 1489f8307e12SArchie Cobbs break; 1490f8307e12SArchie Cobbs } 1491f8307e12SArchie Cobbs 1492f8307e12SArchie Cobbs /* Get a response message with lots of room */ 1493f8307e12SArchie Cobbs NG_MKRESPONSE(rp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 1494f8307e12SArchie Cobbs if (rp == NULL) { 1495f8307e12SArchie Cobbs error = ENOMEM; 1496f8307e12SArchie Cobbs break; 1497f8307e12SArchie Cobbs } 1498f8307e12SArchie Cobbs ascii = (struct ng_mesg *)rp->data; 1499f8307e12SArchie Cobbs 1500f8307e12SArchie Cobbs /* Copy binary message header to response message payload */ 1501f8307e12SArchie Cobbs bcopy(binary, ascii, sizeof(*binary)); 1502f8307e12SArchie Cobbs 1503f8307e12SArchie Cobbs /* Find command by matching typecookie and command number */ 1504f8307e12SArchie Cobbs for (c = here->type->cmdlist; 1505f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 1506f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 1507f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 1508f8307e12SArchie Cobbs break; 1509f8307e12SArchie Cobbs } 1510f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 1511f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 1512f8307e12SArchie Cobbs if (binary->header.typecookie == c->cookie 1513f8307e12SArchie Cobbs && binary->header.cmd == c->cmd) 1514f8307e12SArchie Cobbs break; 1515f8307e12SArchie Cobbs } 1516f8307e12SArchie Cobbs if (c->name == NULL) { 1517f8307e12SArchie Cobbs FREE(rp, M_NETGRAPH); 1518f8307e12SArchie Cobbs error = ENOSYS; 1519f8307e12SArchie Cobbs break; 1520f8307e12SArchie Cobbs } 1521f8307e12SArchie Cobbs } 1522f8307e12SArchie Cobbs 1523f8307e12SArchie Cobbs /* Convert command name to ASCII */ 1524f8307e12SArchie Cobbs snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 1525f8307e12SArchie Cobbs "%s", c->name); 1526f8307e12SArchie Cobbs 1527f8307e12SArchie Cobbs /* Convert command arguments to ASCII */ 1528f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 1529f8307e12SArchie Cobbs c->respType : c->mesgType; 1530f8307e12SArchie Cobbs if (argstype == NULL) 1531f8307e12SArchie Cobbs *ascii->data = '\0'; 1532f8307e12SArchie Cobbs else { 1533f8307e12SArchie Cobbs if ((error = ng_unparse(argstype, 1534f8307e12SArchie Cobbs (u_char *)binary->data, 1535f8307e12SArchie Cobbs ascii->data, bufSize)) != 0) { 1536f8307e12SArchie Cobbs FREE(rp, M_NETGRAPH); 1537f8307e12SArchie Cobbs break; 1538f8307e12SArchie Cobbs } 1539f8307e12SArchie Cobbs } 1540f8307e12SArchie Cobbs 1541f8307e12SArchie Cobbs /* Return the result as struct ng_mesg plus ASCII string */ 1542f8307e12SArchie Cobbs bufSize = strlen(ascii->data) + 1; 1543f8307e12SArchie Cobbs ascii->header.arglen = bufSize; 1544f8307e12SArchie Cobbs rp->header.arglen = sizeof(*ascii) + bufSize; 1545f8307e12SArchie Cobbs *resp = rp; 1546f8307e12SArchie Cobbs break; 1547f8307e12SArchie Cobbs } 1548f8307e12SArchie Cobbs 1549f8307e12SArchie Cobbs case NGM_ASCII2BINARY: 1550f8307e12SArchie Cobbs { 1551f8307e12SArchie Cobbs int bufSize = 2000; /* XXX hard coded constant */ 1552f8307e12SArchie Cobbs const struct ng_cmdlist *c; 1553f8307e12SArchie Cobbs const struct ng_parse_type *argstype; 1554f8307e12SArchie Cobbs struct ng_mesg *rp, *ascii, *binary; 155552ec4a03SArchie Cobbs int off = 0; 1556f8307e12SArchie Cobbs 1557f8307e12SArchie Cobbs /* Data area must contain at least a struct ng_mesg + '\0' */ 1558f8307e12SArchie Cobbs ascii = (struct ng_mesg *)msg->data; 1559f8307e12SArchie Cobbs if (msg->header.arglen < sizeof(*ascii) + 1 1560f8307e12SArchie Cobbs || ascii->header.arglen < 1 1561f8307e12SArchie Cobbs || msg->header.arglen 1562f8307e12SArchie Cobbs < sizeof(*ascii) + ascii->header.arglen) { 1563f8307e12SArchie Cobbs error = EINVAL; 1564f8307e12SArchie Cobbs break; 1565f8307e12SArchie Cobbs } 1566f8307e12SArchie Cobbs ascii->data[ascii->header.arglen - 1] = '\0'; 1567f8307e12SArchie Cobbs 1568f8307e12SArchie Cobbs /* Get a response message with lots of room */ 1569f8307e12SArchie Cobbs NG_MKRESPONSE(rp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 1570f8307e12SArchie Cobbs if (rp == NULL) { 1571f8307e12SArchie Cobbs error = ENOMEM; 1572f8307e12SArchie Cobbs break; 1573f8307e12SArchie Cobbs } 1574f8307e12SArchie Cobbs binary = (struct ng_mesg *)rp->data; 1575f8307e12SArchie Cobbs 1576f8307e12SArchie Cobbs /* Copy ASCII message header to response message payload */ 1577f8307e12SArchie Cobbs bcopy(ascii, binary, sizeof(*ascii)); 1578f8307e12SArchie Cobbs 1579f8307e12SArchie Cobbs /* Find command by matching ASCII command string */ 1580f8307e12SArchie Cobbs for (c = here->type->cmdlist; 1581f8307e12SArchie Cobbs c != NULL && c->name != NULL; c++) { 1582f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 1583f8307e12SArchie Cobbs break; 1584f8307e12SArchie Cobbs } 1585f8307e12SArchie Cobbs if (c == NULL || c->name == NULL) { 1586f8307e12SArchie Cobbs for (c = ng_generic_cmds; c->name != NULL; c++) { 1587f8307e12SArchie Cobbs if (strcmp(ascii->header.cmdstr, c->name) == 0) 1588f8307e12SArchie Cobbs break; 1589f8307e12SArchie Cobbs } 1590f8307e12SArchie Cobbs if (c->name == NULL) { 1591f8307e12SArchie Cobbs FREE(rp, M_NETGRAPH); 1592f8307e12SArchie Cobbs error = ENOSYS; 1593f8307e12SArchie Cobbs break; 1594f8307e12SArchie Cobbs } 1595f8307e12SArchie Cobbs } 1596f8307e12SArchie Cobbs 1597f8307e12SArchie Cobbs /* Convert command name to binary */ 1598f8307e12SArchie Cobbs binary->header.cmd = c->cmd; 1599f8307e12SArchie Cobbs binary->header.typecookie = c->cookie; 1600f8307e12SArchie Cobbs 1601f8307e12SArchie Cobbs /* Convert command arguments to binary */ 1602f8307e12SArchie Cobbs argstype = (binary->header.flags & NGF_RESP) ? 1603f8307e12SArchie Cobbs c->respType : c->mesgType; 1604f8307e12SArchie Cobbs if (argstype == NULL) 1605f8307e12SArchie Cobbs bufSize = 0; 1606f8307e12SArchie Cobbs else { 1607f8307e12SArchie Cobbs if ((error = ng_parse(argstype, ascii->data, 1608f8307e12SArchie Cobbs &off, (u_char *)binary->data, &bufSize)) != 0) { 1609f8307e12SArchie Cobbs FREE(rp, M_NETGRAPH); 1610f8307e12SArchie Cobbs break; 1611f8307e12SArchie Cobbs } 1612f8307e12SArchie Cobbs } 1613f8307e12SArchie Cobbs 1614f8307e12SArchie Cobbs /* Return the result */ 1615f8307e12SArchie Cobbs binary->header.arglen = bufSize; 1616f8307e12SArchie Cobbs rp->header.arglen = sizeof(*binary) + bufSize; 1617f8307e12SArchie Cobbs *resp = rp; 1618f8307e12SArchie Cobbs break; 1619f8307e12SArchie Cobbs } 1620f8307e12SArchie Cobbs 16217095e097SPoul-Henning Kamp case NGM_TEXT_CONFIG: 16224cf49a43SJulian Elischer case NGM_TEXT_STATUS: 16234cf49a43SJulian Elischer /* 16244cf49a43SJulian Elischer * This one is tricky as it passes the command down to the 16254cf49a43SJulian Elischer * actual node, even though it is a generic type command. 16264cf49a43SJulian Elischer * This means we must assume that the msg is already freed 16274cf49a43SJulian Elischer * when control passes back to us. 16284cf49a43SJulian Elischer */ 16294cf49a43SJulian Elischer if (resp == NULL) { 16304cf49a43SJulian Elischer error = EINVAL; 16314cf49a43SJulian Elischer break; 16324cf49a43SJulian Elischer } 16334cf49a43SJulian Elischer if (here->type->rcvmsg != NULL) 1634a4ec03cfSJulian Elischer return((*here->type->rcvmsg)(here, msg, retaddr, 1635a4ec03cfSJulian Elischer resp, lasthook)); 16364cf49a43SJulian Elischer /* Fall through if rcvmsg not supported */ 16374cf49a43SJulian Elischer default: 16384cf49a43SJulian Elischer TRAP_ERROR; 16394cf49a43SJulian Elischer error = EINVAL; 16404cf49a43SJulian Elischer } 16414cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 16424cf49a43SJulian Elischer return (error); 16434cf49a43SJulian Elischer } 16444cf49a43SJulian Elischer 16454cf49a43SJulian Elischer /* 16464cf49a43SJulian Elischer * Send a data packet to a node. If the recipient has no 16474cf49a43SJulian Elischer * 'receive data' method, then silently discard the packet. 1648859a4d16SJulian Elischer * The receiving node may elect to put the data onto the netgraph 1649859a4d16SJulian Elischer * NETISR queue for later delivery. It may do this because it knows there 1650859a4d16SJulian Elischer * is some recursion and wishes to unwind the stack, or because it has 1651859a4d16SJulian Elischer * some suspicion that it is being called at (say) splimp instead of 1652859a4d16SJulian Elischer * splnet. 16534cf49a43SJulian Elischer */ 16544cf49a43SJulian Elischer int 1655a4ec03cfSJulian Elischer ng_send_data(hook_p hook, struct mbuf *m, meta_p meta, 1656859a4d16SJulian Elischer struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 16574cf49a43SJulian Elischer { 1658a4ec03cfSJulian Elischer ng_rcvdata_t *rcvdata; 16594cf49a43SJulian Elischer 1660b2da83c2SArchie Cobbs CHECK_DATA_MBUF(m); 1661859a4d16SJulian Elischer if ((hook == NULL) 1662859a4d16SJulian Elischer || ((hook->flags & HK_INVALID) != 0) 1663859a4d16SJulian Elischer || ((rcvdata = hook->peer->node->type->rcvdata) == NULL)) { 16644cf49a43SJulian Elischer TRAP_ERROR; 16654cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 1666859a4d16SJulian Elischer return (ENOTCONN); 16674cf49a43SJulian Elischer } 1668859a4d16SJulian Elischer if (hook->peer->flags & HK_QUEUE) { 1669859a4d16SJulian Elischer return (ng_queue_data(hook, m, meta)); 1670859a4d16SJulian Elischer } 1671859a4d16SJulian Elischer return ( (*rcvdata)(hook->peer, m, meta, ret_m, ret_meta, resp)); 16724cf49a43SJulian Elischer } 16734cf49a43SJulian Elischer 16744cf49a43SJulian Elischer /* 1675859a4d16SJulian Elischer * Send a queued data packet to a node. 1676859a4d16SJulian Elischer * 1677859a4d16SJulian Elischer * This is meant for data that is being dequeued and should therefore NOT 1678859a4d16SJulian Elischer * be queued again. It ignores the queue flag and should NOT be called 1679859a4d16SJulian Elischer * outside of this file. (thus it is static) 16804cf49a43SJulian Elischer */ 1681859a4d16SJulian Elischer static int 1682859a4d16SJulian Elischer ng_send_data_dont_queue(hook_p hook, struct mbuf *m, meta_p meta, 1683859a4d16SJulian Elischer struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 16844cf49a43SJulian Elischer { 1685a4ec03cfSJulian Elischer ng_rcvdata_t *rcvdata; 16864cf49a43SJulian Elischer 1687b2da83c2SArchie Cobbs CHECK_DATA_MBUF(m); 1688859a4d16SJulian Elischer if ((hook == NULL) 1689859a4d16SJulian Elischer || ((hook->flags & HK_INVALID) != 0) 1690859a4d16SJulian Elischer || ((rcvdata = hook->peer->node->type->rcvdata) == NULL)) { 16914cf49a43SJulian Elischer TRAP_ERROR; 16924cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 1693859a4d16SJulian Elischer return (ENOTCONN); 16944cf49a43SJulian Elischer } 1695859a4d16SJulian Elischer return ((*rcvdata)(hook->peer, m, meta, ret_m, ret_meta, resp)); 16964cf49a43SJulian Elischer } 16974cf49a43SJulian Elischer 1698a096e45aSArchie Cobbs /* 1699a096e45aSArchie Cobbs * Copy a 'meta'. 1700a096e45aSArchie Cobbs * 1701a096e45aSArchie Cobbs * Returns new meta, or NULL if original meta is NULL or ENOMEM. 1702a096e45aSArchie Cobbs */ 1703a096e45aSArchie Cobbs meta_p 1704a096e45aSArchie Cobbs ng_copy_meta(meta_p meta) 1705a096e45aSArchie Cobbs { 1706a096e45aSArchie Cobbs meta_p meta2; 1707a096e45aSArchie Cobbs 1708a096e45aSArchie Cobbs if (meta == NULL) 1709a096e45aSArchie Cobbs return (NULL); 1710a096e45aSArchie Cobbs MALLOC(meta2, meta_p, meta->used_len, M_NETGRAPH, M_NOWAIT); 1711a096e45aSArchie Cobbs if (meta2 == NULL) 1712a096e45aSArchie Cobbs return (NULL); 1713a096e45aSArchie Cobbs meta2->allocated_len = meta->used_len; 1714a096e45aSArchie Cobbs bcopy(meta, meta2, meta->used_len); 1715a096e45aSArchie Cobbs return (meta2); 1716a096e45aSArchie Cobbs } 1717a096e45aSArchie Cobbs 17184cf49a43SJulian Elischer /************************************************************************ 17194cf49a43SJulian Elischer Module routines 17204cf49a43SJulian Elischer ************************************************************************/ 17214cf49a43SJulian Elischer 17224cf49a43SJulian Elischer /* 17234cf49a43SJulian Elischer * Handle the loading/unloading of a netgraph node type module 17244cf49a43SJulian Elischer */ 17254cf49a43SJulian Elischer int 17264cf49a43SJulian Elischer ng_mod_event(module_t mod, int event, void *data) 17274cf49a43SJulian Elischer { 17284cf49a43SJulian Elischer struct ng_type *const type = data; 17294cf49a43SJulian Elischer int s, error = 0; 17304cf49a43SJulian Elischer 17314cf49a43SJulian Elischer switch (event) { 17324cf49a43SJulian Elischer case MOD_LOAD: 17334cf49a43SJulian Elischer 17344cf49a43SJulian Elischer /* Register new netgraph node type */ 17354cf49a43SJulian Elischer s = splnet(); 17364cf49a43SJulian Elischer if ((error = ng_newtype(type)) != 0) { 17374cf49a43SJulian Elischer splx(s); 17384cf49a43SJulian Elischer break; 17394cf49a43SJulian Elischer } 17404cf49a43SJulian Elischer 17414cf49a43SJulian Elischer /* Call type specific code */ 17424cf49a43SJulian Elischer if (type->mod_event != NULL) 17434cf49a43SJulian Elischer if ((error = (*type->mod_event)(mod, event, data)) != 0) 17444cf49a43SJulian Elischer LIST_REMOVE(type, types); 17454cf49a43SJulian Elischer splx(s); 17464cf49a43SJulian Elischer break; 17474cf49a43SJulian Elischer 17484cf49a43SJulian Elischer case MOD_UNLOAD: 17494cf49a43SJulian Elischer s = splnet(); 17504cf49a43SJulian Elischer if (type->refs != 0) /* make sure no nodes exist! */ 17514cf49a43SJulian Elischer error = EBUSY; 17524cf49a43SJulian Elischer else { 17534cf49a43SJulian Elischer if (type->mod_event != NULL) { /* check with type */ 17544cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 17554cf49a43SJulian Elischer if (error != 0) { /* type refuses.. */ 17564cf49a43SJulian Elischer splx(s); 17574cf49a43SJulian Elischer break; 17584cf49a43SJulian Elischer } 17594cf49a43SJulian Elischer } 17604cf49a43SJulian Elischer LIST_REMOVE(type, types); 17614cf49a43SJulian Elischer } 17624cf49a43SJulian Elischer splx(s); 17634cf49a43SJulian Elischer break; 17644cf49a43SJulian Elischer 17654cf49a43SJulian Elischer default: 17664cf49a43SJulian Elischer if (type->mod_event != NULL) 17674cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 17684cf49a43SJulian Elischer else 17694cf49a43SJulian Elischer error = 0; /* XXX ? */ 17704cf49a43SJulian Elischer break; 17714cf49a43SJulian Elischer } 17724cf49a43SJulian Elischer return (error); 17734cf49a43SJulian Elischer } 17744cf49a43SJulian Elischer 17754cf49a43SJulian Elischer /* 17764cf49a43SJulian Elischer * Handle loading and unloading for this code. 17774cf49a43SJulian Elischer * The only thing we need to link into is the NETISR strucure. 17784cf49a43SJulian Elischer */ 17794cf49a43SJulian Elischer static int 17804cf49a43SJulian Elischer ngb_mod_event(module_t mod, int event, void *data) 17814cf49a43SJulian Elischer { 17824cf49a43SJulian Elischer int s, error = 0; 17834cf49a43SJulian Elischer 17844cf49a43SJulian Elischer switch (event) { 17854cf49a43SJulian Elischer case MOD_LOAD: 17864cf49a43SJulian Elischer /* Register line discipline */ 17874cf49a43SJulian Elischer s = splimp(); 17884cf49a43SJulian Elischer error = register_netisr(NETISR_NETGRAPH, ngintr); 17894cf49a43SJulian Elischer splx(s); 17904cf49a43SJulian Elischer break; 17914cf49a43SJulian Elischer case MOD_UNLOAD: 17924cf49a43SJulian Elischer /* You cant unload it because an interface may be using it. */ 17934cf49a43SJulian Elischer error = EBUSY; 17944cf49a43SJulian Elischer break; 17954cf49a43SJulian Elischer default: 17964cf49a43SJulian Elischer error = EOPNOTSUPP; 17974cf49a43SJulian Elischer break; 17984cf49a43SJulian Elischer } 17994cf49a43SJulian Elischer return (error); 18004cf49a43SJulian Elischer } 18014cf49a43SJulian Elischer 18024cf49a43SJulian Elischer static moduledata_t netgraph_mod = { 18034cf49a43SJulian Elischer "netgraph", 18044cf49a43SJulian Elischer ngb_mod_event, 18054cf49a43SJulian Elischer (NULL) 18064cf49a43SJulian Elischer }; 18074cf49a43SJulian Elischer DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 18084cf49a43SJulian Elischer 18094cf49a43SJulian Elischer /************************************************************************ 18104cf49a43SJulian Elischer Queueing routines 18114cf49a43SJulian Elischer ************************************************************************/ 18124cf49a43SJulian Elischer 18134cf49a43SJulian Elischer /* The structure for queueing across ISR switches */ 18144cf49a43SJulian Elischer struct ng_queue_entry { 18154cf49a43SJulian Elischer u_long flags; 18164cf49a43SJulian Elischer struct ng_queue_entry *next; 18174cf49a43SJulian Elischer union { 18184cf49a43SJulian Elischer struct { 18194cf49a43SJulian Elischer hook_p da_hook; /* target hook */ 18204cf49a43SJulian Elischer struct mbuf *da_m; 18214cf49a43SJulian Elischer meta_p da_meta; 18224cf49a43SJulian Elischer } data; 18234cf49a43SJulian Elischer struct { 18244cf49a43SJulian Elischer struct ng_mesg *msg_msg; 18254cf49a43SJulian Elischer node_p msg_node; 1826a4ec03cfSJulian Elischer hook_p msg_lasthook; 1827859a4d16SJulian Elischer char *msg_retaddr; 18284cf49a43SJulian Elischer } msg; 18294cf49a43SJulian Elischer } body; 18304cf49a43SJulian Elischer }; 18314cf49a43SJulian Elischer #define NGQF_DATA 0x01 /* the queue element is data */ 18324cf49a43SJulian Elischer #define NGQF_MESG 0x02 /* the queue element is a message */ 18334cf49a43SJulian Elischer 18344cf49a43SJulian Elischer static struct ng_queue_entry *ngqbase; /* items to be unqueued */ 18354cf49a43SJulian Elischer static struct ng_queue_entry *ngqlast; /* last item queued */ 18364cf49a43SJulian Elischer static const int ngqroom = 64; /* max items to queue */ 18374cf49a43SJulian Elischer static int ngqsize; /* number of items in queue */ 18384cf49a43SJulian Elischer 18394cf49a43SJulian Elischer static struct ng_queue_entry *ngqfree; /* free ones */ 18404cf49a43SJulian Elischer static const int ngqfreemax = 16;/* cache at most this many */ 18414cf49a43SJulian Elischer static int ngqfreesize; /* number of cached entries */ 18424cf49a43SJulian Elischer 18434cf49a43SJulian Elischer /* 18444cf49a43SJulian Elischer * Get a queue entry 18454cf49a43SJulian Elischer */ 18464cf49a43SJulian Elischer static struct ng_queue_entry * 18474cf49a43SJulian Elischer ng_getqblk(void) 18484cf49a43SJulian Elischer { 18494cf49a43SJulian Elischer register struct ng_queue_entry *q; 18504cf49a43SJulian Elischer int s; 18514cf49a43SJulian Elischer 18524cf49a43SJulian Elischer /* Could be guarding against tty ints or whatever */ 18534cf49a43SJulian Elischer s = splhigh(); 18544cf49a43SJulian Elischer 18554cf49a43SJulian Elischer /* Try get a cached queue block, or else allocate a new one */ 18564cf49a43SJulian Elischer if ((q = ngqfree) == NULL) { 18574cf49a43SJulian Elischer splx(s); 18584cf49a43SJulian Elischer if (ngqsize < ngqroom) { /* don't worry about races */ 18594cf49a43SJulian Elischer MALLOC(q, struct ng_queue_entry *, 18604cf49a43SJulian Elischer sizeof(*q), M_NETGRAPH, M_NOWAIT); 18614cf49a43SJulian Elischer } 18624cf49a43SJulian Elischer } else { 18634cf49a43SJulian Elischer ngqfree = q->next; 18644cf49a43SJulian Elischer ngqfreesize--; 18654cf49a43SJulian Elischer splx(s); 18664cf49a43SJulian Elischer } 18674cf49a43SJulian Elischer return (q); 18684cf49a43SJulian Elischer } 18694cf49a43SJulian Elischer 18704cf49a43SJulian Elischer /* 18714cf49a43SJulian Elischer * Release a queue entry 18724cf49a43SJulian Elischer */ 18734cf49a43SJulian Elischer #define RETURN_QBLK(q) \ 18744cf49a43SJulian Elischer do { \ 18754cf49a43SJulian Elischer int s; \ 18764cf49a43SJulian Elischer if (ngqfreesize < ngqfreemax) { /* don't worry about races */ \ 18774cf49a43SJulian Elischer s = splhigh(); \ 18784cf49a43SJulian Elischer (q)->next = ngqfree; \ 18794cf49a43SJulian Elischer ngqfree = (q); \ 18804cf49a43SJulian Elischer ngqfreesize++; \ 18814cf49a43SJulian Elischer splx(s); \ 18824cf49a43SJulian Elischer } else { \ 18834cf49a43SJulian Elischer FREE((q), M_NETGRAPH); \ 18844cf49a43SJulian Elischer } \ 18854cf49a43SJulian Elischer } while (0) 18864cf49a43SJulian Elischer 18874cf49a43SJulian Elischer /* 18884cf49a43SJulian Elischer * Running at a raised (but we don't know which) processor priority level, 18894cf49a43SJulian Elischer * put the data onto a queue to be picked up by another PPL (probably splnet) 18904cf49a43SJulian Elischer */ 18914cf49a43SJulian Elischer int 18924cf49a43SJulian Elischer ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta) 18934cf49a43SJulian Elischer { 18944cf49a43SJulian Elischer struct ng_queue_entry *q; 18954cf49a43SJulian Elischer int s; 18964cf49a43SJulian Elischer 18974cf49a43SJulian Elischer if (hook == NULL) { 18984cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 18994cf49a43SJulian Elischer return (0); 19004cf49a43SJulian Elischer } 19014cf49a43SJulian Elischer if ((q = ng_getqblk()) == NULL) { 19024cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 19034cf49a43SJulian Elischer return (ENOBUFS); 19044cf49a43SJulian Elischer } 19054cf49a43SJulian Elischer 19064cf49a43SJulian Elischer /* Fill out the contents */ 19074cf49a43SJulian Elischer q->flags = NGQF_DATA; 19084cf49a43SJulian Elischer q->next = NULL; 19094cf49a43SJulian Elischer q->body.data.da_hook = hook; 19104cf49a43SJulian Elischer q->body.data.da_m = m; 19114cf49a43SJulian Elischer q->body.data.da_meta = meta; 1912e8a49db2SJulian Elischer s = splhigh(); /* protect refs and queue */ 19134cf49a43SJulian Elischer hook->refs++; /* don't let it go away while on the queue */ 19144cf49a43SJulian Elischer 19154cf49a43SJulian Elischer /* Put it on the queue */ 19164cf49a43SJulian Elischer if (ngqbase) { 19174cf49a43SJulian Elischer ngqlast->next = q; 19184cf49a43SJulian Elischer } else { 19194cf49a43SJulian Elischer ngqbase = q; 19204cf49a43SJulian Elischer } 19214cf49a43SJulian Elischer ngqlast = q; 19224cf49a43SJulian Elischer ngqsize++; 19234cf49a43SJulian Elischer splx(s); 19244cf49a43SJulian Elischer 19254cf49a43SJulian Elischer /* Schedule software interrupt to handle it later */ 19264cf49a43SJulian Elischer schednetisr(NETISR_NETGRAPH); 19274cf49a43SJulian Elischer return (0); 19284cf49a43SJulian Elischer } 19294cf49a43SJulian Elischer 19304cf49a43SJulian Elischer /* 19314cf49a43SJulian Elischer * Running at a raised (but we don't know which) processor priority level, 19324cf49a43SJulian Elischer * put the msg onto a queue to be picked up by another PPL (probably splnet) 1933859a4d16SJulian Elischer * Either specify an address, or a hook to traverse. 1934859a4d16SJulian Elischer * The return address can be specified, or it will be pointed at this node. 19354cf49a43SJulian Elischer */ 19364cf49a43SJulian Elischer int 1937859a4d16SJulian Elischer ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address, hook_p hook,char *retaddr) 19384cf49a43SJulian Elischer { 19394cf49a43SJulian Elischer register struct ng_queue_entry *q; 19404cf49a43SJulian Elischer int s; 19414cf49a43SJulian Elischer node_p dest = NULL; 19424cf49a43SJulian Elischer int error; 1943a4ec03cfSJulian Elischer hook_p lasthook = NULL; 19444cf49a43SJulian Elischer 1945859a4d16SJulian Elischer /* 1946859a4d16SJulian Elischer * Find the target node. 1947859a4d16SJulian Elischer * If there is a HOOK argument, then use that in preference 1948859a4d16SJulian Elischer * to the address. 1949859a4d16SJulian Elischer */ 1950859a4d16SJulian Elischer if (hook) { 1951859a4d16SJulian Elischer lasthook = hook->peer; 1952859a4d16SJulian Elischer dest = lasthook->node; 1953859a4d16SJulian Elischer } else { 1954859a4d16SJulian Elischer error = ng_path2node(here, address, &dest, &lasthook); 19554cf49a43SJulian Elischer if (error) { 19564cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 19574cf49a43SJulian Elischer return (error); 19584cf49a43SJulian Elischer } 1959859a4d16SJulian Elischer } 1960859a4d16SJulian Elischer 1961859a4d16SJulian Elischer if (retaddr == NULL) { 1962859a4d16SJulian Elischer /* 1963859a4d16SJulian Elischer * Now fill out the return address, 1964859a4d16SJulian Elischer * i.e. the name/ID of the sender. (If we didn't get one) 1965859a4d16SJulian Elischer */ 1966859a4d16SJulian Elischer MALLOC(retaddr, char *, NG_NODELEN + 2, M_NETGRAPH, M_NOWAIT); 1967859a4d16SJulian Elischer if (retaddr == NULL) { 1968859a4d16SJulian Elischer TRAP_ERROR; 1969859a4d16SJulian Elischer return (ENOMEM); 1970859a4d16SJulian Elischer } 1971859a4d16SJulian Elischer if (here->name != NULL) 1972859a4d16SJulian Elischer sprintf(retaddr, "%s:", here->name); 1973859a4d16SJulian Elischer else 1974859a4d16SJulian Elischer sprintf(retaddr, "[%x]:", ng_node2ID(here)); 1975859a4d16SJulian Elischer } 1976859a4d16SJulian Elischer 19774cf49a43SJulian Elischer if ((q = ng_getqblk()) == NULL) { 19784cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 19794cf49a43SJulian Elischer if (retaddr) 19804cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 19814cf49a43SJulian Elischer return (ENOBUFS); 19824cf49a43SJulian Elischer } 19834cf49a43SJulian Elischer 19844cf49a43SJulian Elischer /* Fill out the contents */ 19854cf49a43SJulian Elischer q->flags = NGQF_MESG; 19864cf49a43SJulian Elischer q->next = NULL; 19874cf49a43SJulian Elischer q->body.msg.msg_node = dest; 19884cf49a43SJulian Elischer q->body.msg.msg_msg = msg; 1989859a4d16SJulian Elischer q->body.msg.msg_retaddr = retaddr; /* XXX malloc'd, give it away */ 1990859a4d16SJulian Elischer q->body.msg.msg_lasthook = lasthook; /* XXX needs reference */ 1991e8a49db2SJulian Elischer s = splhigh(); /* protect refs and queue */ 19924cf49a43SJulian Elischer dest->refs++; /* don't let it go away while on the queue */ 1993a4ec03cfSJulian Elischer if (lasthook) 1994a4ec03cfSJulian Elischer lasthook->refs++; /* same for the hook */ 19954cf49a43SJulian Elischer 19964cf49a43SJulian Elischer /* Put it on the queue */ 19974cf49a43SJulian Elischer if (ngqbase) { 19984cf49a43SJulian Elischer ngqlast->next = q; 19994cf49a43SJulian Elischer } else { 20004cf49a43SJulian Elischer ngqbase = q; 20014cf49a43SJulian Elischer } 20024cf49a43SJulian Elischer ngqlast = q; 20034cf49a43SJulian Elischer ngqsize++; 20044cf49a43SJulian Elischer splx(s); 20054cf49a43SJulian Elischer 20064cf49a43SJulian Elischer /* Schedule software interrupt to handle it later */ 20074cf49a43SJulian Elischer schednetisr(NETISR_NETGRAPH); 20084cf49a43SJulian Elischer return (0); 20094cf49a43SJulian Elischer } 20104cf49a43SJulian Elischer 20114cf49a43SJulian Elischer /* 20124cf49a43SJulian Elischer * Pick an item off the queue, process it, and dispose of the queue entry. 20134cf49a43SJulian Elischer * Should be running at splnet. 20144cf49a43SJulian Elischer */ 20154cf49a43SJulian Elischer static void 20164cf49a43SJulian Elischer ngintr(void) 20174cf49a43SJulian Elischer { 20184cf49a43SJulian Elischer hook_p hook; 20194cf49a43SJulian Elischer struct ng_queue_entry *ngq; 20204cf49a43SJulian Elischer struct mbuf *m; 20214cf49a43SJulian Elischer meta_p meta; 20224cf49a43SJulian Elischer void *retaddr; 20234cf49a43SJulian Elischer struct ng_mesg *msg; 20244cf49a43SJulian Elischer node_p node; 20254cf49a43SJulian Elischer int error = 0; 20264cf49a43SJulian Elischer int s; 20274cf49a43SJulian Elischer 20284cf49a43SJulian Elischer while (1) { 20294cf49a43SJulian Elischer s = splhigh(); 20304cf49a43SJulian Elischer if ((ngq = ngqbase)) { 20314cf49a43SJulian Elischer ngqbase = ngq->next; 20324cf49a43SJulian Elischer ngqsize--; 20334cf49a43SJulian Elischer } 20344cf49a43SJulian Elischer splx(s); 20354cf49a43SJulian Elischer if (ngq == NULL) 20364cf49a43SJulian Elischer return; 20374cf49a43SJulian Elischer switch (ngq->flags) { 20384cf49a43SJulian Elischer case NGQF_DATA: 20394cf49a43SJulian Elischer hook = ngq->body.data.da_hook; 20404cf49a43SJulian Elischer m = ngq->body.data.da_m; 20414cf49a43SJulian Elischer meta = ngq->body.data.da_meta; 20424cf49a43SJulian Elischer RETURN_QBLK(ngq); 2043859a4d16SJulian Elischer ng_send_data_dont_queue(hook, m, meta, 2044859a4d16SJulian Elischer NULL, NULL, NULL); 2045859a4d16SJulian Elischer m = NULL; 2046859a4d16SJulian Elischer meta = NULL; 20474cf49a43SJulian Elischer ng_unref_hook(hook); 20484cf49a43SJulian Elischer break; 20494cf49a43SJulian Elischer case NGQF_MESG: 20504cf49a43SJulian Elischer node = ngq->body.msg.msg_node; 20514cf49a43SJulian Elischer msg = ngq->body.msg.msg_msg; 20524cf49a43SJulian Elischer retaddr = ngq->body.msg.msg_retaddr; 2053a4ec03cfSJulian Elischer hook = ngq->body.msg.msg_lasthook; 20544cf49a43SJulian Elischer RETURN_QBLK(ngq); 2055a4ec03cfSJulian Elischer if (hook) { 2056e8a49db2SJulian Elischer if ((hook->flags & HK_INVALID) != 0) { 2057e8a49db2SJulian Elischer /* If the hook has been zapped 2058a4ec03cfSJulian Elischer then we can't use it */ 2059a4ec03cfSJulian Elischer ng_unref_hook(hook); 2060a4ec03cfSJulian Elischer hook = NULL; 2061a4ec03cfSJulian Elischer } 2062a4ec03cfSJulian Elischer } 2063a4ec03cfSJulian Elischer /* similarly, if the node is a zombie.. */ 20644cf49a43SJulian Elischer if (node->flags & NG_INVALID) { 20654cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 20664cf49a43SJulian Elischer } else { 20674cf49a43SJulian Elischer CALL_MSG_HANDLER(error, node, msg, 2068a4ec03cfSJulian Elischer retaddr, NULL, hook); 20694cf49a43SJulian Elischer } 2070e8a49db2SJulian Elischer if (hook) 2071e8a49db2SJulian Elischer ng_unref_hook(hook); 20724cf49a43SJulian Elischer ng_unref(node); 20734cf49a43SJulian Elischer if (retaddr) 20744cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 20754cf49a43SJulian Elischer break; 20764cf49a43SJulian Elischer default: 20774cf49a43SJulian Elischer RETURN_QBLK(ngq); 20784cf49a43SJulian Elischer } 20794cf49a43SJulian Elischer } 20804cf49a43SJulian Elischer } 20814cf49a43SJulian Elischer 20824cf49a43SJulian Elischer 2083