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 * 374cf49a43SJulian Elischer * Authors: Julian Elischer <julian@whistle.com> 384cf49a43SJulian Elischer * Archie Cobbs <archie@whistle.com> 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> 574cf49a43SJulian Elischer #include <sys/socketvar.h> 584cf49a43SJulian Elischer 594cf49a43SJulian Elischer #include <net/netisr.h> 604cf49a43SJulian Elischer 614cf49a43SJulian Elischer #include <netgraph/ng_message.h> 624cf49a43SJulian Elischer #include <netgraph/netgraph.h> 634cf49a43SJulian Elischer 644cf49a43SJulian Elischer /* List of all nodes */ 654cf49a43SJulian Elischer static LIST_HEAD(, ng_node) nodelist; 664cf49a43SJulian Elischer 674cf49a43SJulian Elischer /* List of installed types */ 684cf49a43SJulian Elischer static LIST_HEAD(, ng_type) typelist; 694cf49a43SJulian Elischer 70dc90cad9SJulian Elischer /* Hash releted definitions */ 71dc90cad9SJulian Elischer #define ID_HASH_SIZE 32 /* most systems wont need even this many */ 72dc90cad9SJulian Elischer static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE]; 73dc90cad9SJulian Elischer /* Don't nead to initialise them because it's a LIST */ 74dc90cad9SJulian Elischer 754cf49a43SJulian Elischer /* Internal functions */ 764cf49a43SJulian Elischer static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 774cf49a43SJulian Elischer static int ng_connect(hook_p hook1, hook_p hook2); 784cf49a43SJulian Elischer static void ng_disconnect_hook(hook_p hook); 794cf49a43SJulian Elischer static int ng_generic_msg(node_p here, struct ng_mesg *msg, 804cf49a43SJulian Elischer const char *retaddr, struct ng_mesg ** resp); 81dc90cad9SJulian Elischer static ng_ID_t ng_decodeidname(const char *name); 824cf49a43SJulian Elischer static int ngb_mod_event(module_t mod, int event, void *data); 834cf49a43SJulian Elischer static void ngintr(void); 844cf49a43SJulian Elischer 854cf49a43SJulian Elischer /* Our own netgraph malloc type */ 864cf49a43SJulian Elischer MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 874cf49a43SJulian Elischer 884cf49a43SJulian Elischer /* Set this to Debugger("X") to catch all errors as they occur */ 894cf49a43SJulian Elischer #ifndef TRAP_ERROR 904cf49a43SJulian Elischer #define TRAP_ERROR 914cf49a43SJulian Elischer #endif 924cf49a43SJulian Elischer 93dc90cad9SJulian Elischer static ng_ID_t nextID = 1; 94dc90cad9SJulian Elischer 95dc90cad9SJulian Elischer 964cf49a43SJulian Elischer /************************************************************************ 974cf49a43SJulian Elischer Node routines 984cf49a43SJulian Elischer ************************************************************************/ 994cf49a43SJulian Elischer 1004cf49a43SJulian Elischer /* 1014cf49a43SJulian Elischer * Instantiate a node of the requested type 1024cf49a43SJulian Elischer */ 1034cf49a43SJulian Elischer int 1044cf49a43SJulian Elischer ng_make_node(const char *typename, node_p *nodepp) 1054cf49a43SJulian Elischer { 1064cf49a43SJulian Elischer struct ng_type *type; 1074cf49a43SJulian Elischer 1084cf49a43SJulian Elischer /* Check that the type makes sense */ 1094cf49a43SJulian Elischer if (typename == NULL) { 1104cf49a43SJulian Elischer TRAP_ERROR; 1114cf49a43SJulian Elischer return (EINVAL); 1124cf49a43SJulian Elischer } 1134cf49a43SJulian Elischer 1144cf49a43SJulian Elischer /* Locate the node type */ 1154cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) { 1164cf49a43SJulian Elischer char *path, filename[NG_TYPELEN + 4]; 1174cf49a43SJulian Elischer linker_file_t lf; 1184cf49a43SJulian Elischer int error; 1194cf49a43SJulian Elischer 1204cf49a43SJulian Elischer /* Not found, try to load it as a loadable module */ 1214cf49a43SJulian Elischer snprintf(filename, sizeof(filename), "ng_%s.ko", typename); 1224cf49a43SJulian Elischer if ((path = linker_search_path(filename)) == NULL) 1234cf49a43SJulian Elischer return (ENXIO); 1244cf49a43SJulian Elischer error = linker_load_file(path, &lf); 1254cf49a43SJulian Elischer FREE(path, M_LINKER); 1264cf49a43SJulian Elischer if (error != 0) 1274cf49a43SJulian Elischer return (error); 1284cf49a43SJulian Elischer lf->userrefs++; /* pretend loaded by the syscall */ 1294cf49a43SJulian Elischer 1304cf49a43SJulian Elischer /* Try again, as now the type should have linked itself in */ 1314cf49a43SJulian Elischer if ((type = ng_findtype(typename)) == NULL) 1324cf49a43SJulian Elischer return (ENXIO); 1334cf49a43SJulian Elischer } 1344cf49a43SJulian Elischer 1354cf49a43SJulian Elischer /* Call the constructor */ 1364cf49a43SJulian Elischer if (type->constructor != NULL) 1374cf49a43SJulian Elischer return ((*type->constructor)(nodepp)); 1384cf49a43SJulian Elischer else 1394cf49a43SJulian Elischer return (ng_make_node_common(type, nodepp)); 1404cf49a43SJulian Elischer } 1414cf49a43SJulian Elischer 1424cf49a43SJulian Elischer /* 1434cf49a43SJulian Elischer * Generic node creation. Called by node constructors. 1444cf49a43SJulian Elischer * The returned node has a reference count of 1. 1454cf49a43SJulian Elischer */ 1464cf49a43SJulian Elischer int 1474cf49a43SJulian Elischer ng_make_node_common(struct ng_type *type, node_p *nodepp) 1484cf49a43SJulian Elischer { 1494cf49a43SJulian Elischer node_p node; 1504cf49a43SJulian Elischer 1514cf49a43SJulian Elischer /* Require the node type to have been already installed */ 1524cf49a43SJulian Elischer if (ng_findtype(type->name) == NULL) { 1534cf49a43SJulian Elischer TRAP_ERROR; 1544cf49a43SJulian Elischer return (EINVAL); 1554cf49a43SJulian Elischer } 1564cf49a43SJulian Elischer 1574cf49a43SJulian Elischer /* Make a node and try attach it to the type */ 1584cf49a43SJulian Elischer MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_WAITOK); 1594cf49a43SJulian Elischer if (node == NULL) { 1604cf49a43SJulian Elischer TRAP_ERROR; 1614cf49a43SJulian Elischer return (ENOMEM); 1624cf49a43SJulian Elischer } 1634cf49a43SJulian Elischer bzero(node, sizeof(*node)); 1644cf49a43SJulian Elischer node->type = type; 1654cf49a43SJulian Elischer node->refs++; /* note reference */ 1664cf49a43SJulian Elischer type->refs++; 1674cf49a43SJulian Elischer 1684cf49a43SJulian Elischer /* Link us into the node linked list */ 1694cf49a43SJulian Elischer LIST_INSERT_HEAD(&nodelist, node, nodes); 1704cf49a43SJulian Elischer 1714cf49a43SJulian Elischer /* Initialize hook list for new node */ 1724cf49a43SJulian Elischer LIST_INIT(&node->hooks); 1734cf49a43SJulian Elischer 174dc90cad9SJulian Elischer /* get an ID and put us in the hash chain */ 175dc90cad9SJulian Elischer node->ID = nextID++; /* 137 per second for 1 year before wrap */ 176dc90cad9SJulian Elischer LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes); 177dc90cad9SJulian Elischer 1784cf49a43SJulian Elischer /* Done */ 1794cf49a43SJulian Elischer *nodepp = node; 1804cf49a43SJulian Elischer return (0); 1814cf49a43SJulian Elischer } 1824cf49a43SJulian Elischer 1834cf49a43SJulian Elischer /* 1844cf49a43SJulian Elischer * Forceably start the shutdown process on a node. Either call 1854cf49a43SJulian Elischer * it's shutdown method, or do the default shutdown if there is 1864cf49a43SJulian Elischer * no type-specific method. 1874cf49a43SJulian Elischer * 1884cf49a43SJulian Elischer * Persistent nodes must have a type-specific method which 1894cf49a43SJulian Elischer * resets the NG_INVALID flag. 1904cf49a43SJulian Elischer */ 1914cf49a43SJulian Elischer void 1924cf49a43SJulian Elischer ng_rmnode(node_p node) 1934cf49a43SJulian Elischer { 1944cf49a43SJulian Elischer /* Check if it's already shutting down */ 1954cf49a43SJulian Elischer if ((node->flags & NG_INVALID) != 0) 1964cf49a43SJulian Elischer return; 1974cf49a43SJulian Elischer 1984cf49a43SJulian Elischer /* Add an extra reference so it doesn't go away during this */ 1994cf49a43SJulian Elischer node->refs++; 2004cf49a43SJulian Elischer 2014cf49a43SJulian Elischer /* Mark it invalid so any newcomers know not to try use it */ 2024cf49a43SJulian Elischer node->flags |= NG_INVALID; 2034cf49a43SJulian Elischer 2044cf49a43SJulian Elischer /* Ask the type if it has anything to do in this case */ 2054cf49a43SJulian Elischer if (node->type && node->type->shutdown) 2064cf49a43SJulian Elischer (*node->type->shutdown)(node); 2074cf49a43SJulian Elischer else { /* do the default thing */ 2084cf49a43SJulian Elischer ng_unname(node); 2094cf49a43SJulian Elischer ng_cutlinks(node); 2104cf49a43SJulian Elischer ng_unref(node); 2114cf49a43SJulian Elischer } 2124cf49a43SJulian Elischer 2134cf49a43SJulian Elischer /* Remove extra reference, possibly the last */ 2144cf49a43SJulian Elischer ng_unref(node); 2154cf49a43SJulian Elischer } 2164cf49a43SJulian Elischer 2174cf49a43SJulian Elischer /* 2184cf49a43SJulian Elischer * Called by the destructor to remove any STANDARD external references 2194cf49a43SJulian Elischer */ 2204cf49a43SJulian Elischer void 2214cf49a43SJulian Elischer ng_cutlinks(node_p node) 2224cf49a43SJulian Elischer { 2234cf49a43SJulian Elischer hook_p hook; 2244cf49a43SJulian Elischer 2254cf49a43SJulian Elischer /* Make sure that this is set to stop infinite loops */ 2264cf49a43SJulian Elischer node->flags |= NG_INVALID; 2274cf49a43SJulian Elischer 2284cf49a43SJulian Elischer /* If we have sleepers, wake them up; they'll see NG_INVALID */ 2294cf49a43SJulian Elischer if (node->sleepers) 2304cf49a43SJulian Elischer wakeup(node); 2314cf49a43SJulian Elischer 2324cf49a43SJulian Elischer /* Notify all remaining connected nodes to disconnect */ 2334cf49a43SJulian Elischer while ((hook = LIST_FIRST(&node->hooks)) != NULL) 2344cf49a43SJulian Elischer ng_destroy_hook(hook); 2354cf49a43SJulian Elischer } 2364cf49a43SJulian Elischer 2374cf49a43SJulian Elischer /* 2384cf49a43SJulian Elischer * Remove a reference to the node, possibly the last 2394cf49a43SJulian Elischer */ 2404cf49a43SJulian Elischer void 2414cf49a43SJulian Elischer ng_unref(node_p node) 2424cf49a43SJulian Elischer { 2434cf49a43SJulian Elischer if (--node->refs <= 0) { 2444cf49a43SJulian Elischer node->type->refs--; 2454cf49a43SJulian Elischer LIST_REMOVE(node, nodes); 246dc90cad9SJulian Elischer LIST_REMOVE(node, idnodes); 2474cf49a43SJulian Elischer FREE(node, M_NETGRAPH); 2484cf49a43SJulian Elischer } 2494cf49a43SJulian Elischer } 2504cf49a43SJulian Elischer 2514cf49a43SJulian Elischer /* 2524cf49a43SJulian Elischer * Wait for a node to come ready. Returns a node with a reference count; 2534cf49a43SJulian Elischer * don't forget to drop it when we are done with it using ng_release_node(). 2544cf49a43SJulian Elischer */ 2554cf49a43SJulian Elischer int 2564cf49a43SJulian Elischer ng_wait_node(node_p node, char *msg) 2574cf49a43SJulian Elischer { 2584cf49a43SJulian Elischer int s, error = 0; 2594cf49a43SJulian Elischer 2604cf49a43SJulian Elischer if (msg == NULL) 2614cf49a43SJulian Elischer msg = "netgraph"; 2624cf49a43SJulian Elischer s = splnet(); 2634cf49a43SJulian Elischer node->sleepers++; 2644cf49a43SJulian Elischer node->refs++; /* the sleeping process counts as a reference */ 2654cf49a43SJulian Elischer while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY) 2664cf49a43SJulian Elischer error = tsleep(node, (PZERO + 1) | PCATCH, msg, 0); 2674cf49a43SJulian Elischer node->sleepers--; 2684cf49a43SJulian Elischer if (node->flags & NG_INVALID) { 2694cf49a43SJulian Elischer TRAP_ERROR; 2704cf49a43SJulian Elischer error = ENXIO; 2714cf49a43SJulian Elischer } else { 2724cf49a43SJulian Elischer #ifdef DIAGNOSTIC 2734cf49a43SJulian Elischer if (node->refs == 1) { 2744cf49a43SJulian Elischer panic(__FUNCTION__); 2754cf49a43SJulian Elischer error = ENXIO; 2764cf49a43SJulian Elischer } 2774cf49a43SJulian Elischer #endif 2784cf49a43SJulian Elischer node->flags |= NG_BUSY; 2794cf49a43SJulian Elischer } 2804cf49a43SJulian Elischer splx(s); 2814cf49a43SJulian Elischer 2824cf49a43SJulian Elischer /* Release the reference we had on it */ 2834cf49a43SJulian Elischer if (error != 0) 2844cf49a43SJulian Elischer ng_unref(node); 2854cf49a43SJulian Elischer return error; 2864cf49a43SJulian Elischer } 2874cf49a43SJulian Elischer 2884cf49a43SJulian Elischer /* 2894cf49a43SJulian Elischer * Release a node acquired via ng_wait_node() 2904cf49a43SJulian Elischer */ 2914cf49a43SJulian Elischer void 2924cf49a43SJulian Elischer ng_release_node(node_p node) 2934cf49a43SJulian Elischer { 2944cf49a43SJulian Elischer /* Declare that we don't want it */ 2954cf49a43SJulian Elischer node->flags &= ~NG_BUSY; 2964cf49a43SJulian Elischer 2974cf49a43SJulian Elischer /* If we have sleepers, then wake them up */ 2984cf49a43SJulian Elischer if (node->sleepers) 2994cf49a43SJulian Elischer wakeup(node); 3004cf49a43SJulian Elischer 3014cf49a43SJulian Elischer /* We also have a reference.. drop it too */ 3024cf49a43SJulian Elischer ng_unref(node); 3034cf49a43SJulian Elischer } 3044cf49a43SJulian Elischer 3054cf49a43SJulian Elischer /************************************************************************ 306dc90cad9SJulian Elischer Node ID handling 307dc90cad9SJulian Elischer ************************************************************************/ 308dc90cad9SJulian Elischer static node_p 309dc90cad9SJulian Elischer ng_ID2node(ng_ID_t ID) 310dc90cad9SJulian Elischer { 311dc90cad9SJulian Elischer node_p np; 312dc90cad9SJulian Elischer LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) { 313dc90cad9SJulian Elischer if (np->ID == ID) 314dc90cad9SJulian Elischer break; 315dc90cad9SJulian Elischer } 316dc90cad9SJulian Elischer return(np); 317dc90cad9SJulian Elischer } 318dc90cad9SJulian Elischer 319dc90cad9SJulian Elischer ng_ID_t 320dc90cad9SJulian Elischer ng_node2ID(node_p node) 321dc90cad9SJulian Elischer { 322dc90cad9SJulian Elischer return (node->ID); 323dc90cad9SJulian Elischer } 324dc90cad9SJulian Elischer 325dc90cad9SJulian Elischer /************************************************************************ 3264cf49a43SJulian Elischer Node name handling 3274cf49a43SJulian Elischer ************************************************************************/ 3284cf49a43SJulian Elischer 3294cf49a43SJulian Elischer /* 3304cf49a43SJulian Elischer * Assign a node a name. Once assigned, the name cannot be changed. 3314cf49a43SJulian Elischer */ 3324cf49a43SJulian Elischer int 3334cf49a43SJulian Elischer ng_name_node(node_p node, const char *name) 3344cf49a43SJulian Elischer { 3354cf49a43SJulian Elischer int i; 3364cf49a43SJulian Elischer 3374cf49a43SJulian Elischer /* Check the name is valid */ 3384cf49a43SJulian Elischer for (i = 0; i < NG_NODELEN + 1; i++) { 3394cf49a43SJulian Elischer if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 3404cf49a43SJulian Elischer break; 3414cf49a43SJulian Elischer } 3424cf49a43SJulian Elischer if (i == 0 || name[i] != '\0') { 3434cf49a43SJulian Elischer TRAP_ERROR; 3444cf49a43SJulian Elischer return (EINVAL); 3454cf49a43SJulian Elischer } 346dc90cad9SJulian Elischer if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 3474cf49a43SJulian Elischer TRAP_ERROR; 3484cf49a43SJulian Elischer return (EINVAL); 3494cf49a43SJulian Elischer } 3504cf49a43SJulian Elischer 3514cf49a43SJulian Elischer /* Check the node isn't already named */ 3524cf49a43SJulian Elischer if (node->name != NULL) { 3534cf49a43SJulian Elischer TRAP_ERROR; 3544cf49a43SJulian Elischer return (EISCONN); 3554cf49a43SJulian Elischer } 3564cf49a43SJulian Elischer 3574cf49a43SJulian Elischer /* Check the name isn't already being used */ 3584cf49a43SJulian Elischer if (ng_findname(node, name) != NULL) { 3594cf49a43SJulian Elischer TRAP_ERROR; 3604cf49a43SJulian Elischer return (EADDRINUSE); 3614cf49a43SJulian Elischer } 3624cf49a43SJulian Elischer 3634cf49a43SJulian Elischer /* Allocate space and copy it */ 3644cf49a43SJulian Elischer MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK); 3654cf49a43SJulian Elischer if (node->name == NULL) { 3664cf49a43SJulian Elischer TRAP_ERROR; 3674cf49a43SJulian Elischer return (ENOMEM); 3684cf49a43SJulian Elischer } 3694cf49a43SJulian Elischer strcpy(node->name, name); 3704cf49a43SJulian Elischer 3714cf49a43SJulian Elischer /* The name counts as a reference */ 3724cf49a43SJulian Elischer node->refs++; 3734cf49a43SJulian Elischer return (0); 3744cf49a43SJulian Elischer } 3754cf49a43SJulian Elischer 3764cf49a43SJulian Elischer /* 3774cf49a43SJulian Elischer * Find a node by absolute name. The name should NOT end with ':' 3784cf49a43SJulian Elischer * The name "." means "this node" and "[xxx]" means "the node 3794cf49a43SJulian Elischer * with ID (ie, at address) xxx". 3804cf49a43SJulian Elischer * 3814cf49a43SJulian Elischer * Returns the node if found, else NULL. 3824cf49a43SJulian Elischer */ 3834cf49a43SJulian Elischer node_p 3844cf49a43SJulian Elischer ng_findname(node_p this, const char *name) 3854cf49a43SJulian Elischer { 386dc90cad9SJulian Elischer node_p node; 387dc90cad9SJulian Elischer ng_ID_t temp; 3884cf49a43SJulian Elischer 3894cf49a43SJulian Elischer /* "." means "this node" */ 3904cf49a43SJulian Elischer if (strcmp(name, ".") == 0) 3914cf49a43SJulian Elischer return(this); 3924cf49a43SJulian Elischer 3934cf49a43SJulian Elischer /* Check for name-by-ID */ 394dc90cad9SJulian Elischer if ((temp = ng_decodeidname(name)) != 0) { 395dc90cad9SJulian Elischer return (ng_ID2node(temp)); 3964cf49a43SJulian Elischer } 3974cf49a43SJulian Elischer 3984cf49a43SJulian Elischer /* Find node by name */ 3994cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 4004cf49a43SJulian Elischer if (node->name != NULL && strcmp(node->name, name) == 0) 4014cf49a43SJulian Elischer break; 4024cf49a43SJulian Elischer } 4034cf49a43SJulian Elischer return (node); 4044cf49a43SJulian Elischer } 4054cf49a43SJulian Elischer 4064cf49a43SJulian Elischer /* 407dc90cad9SJulian Elischer * Decode a ID name, eg. "[f03034de]". Returns 0 if the 408dc90cad9SJulian Elischer * string is not valid, otherwise returns the value. 4094cf49a43SJulian Elischer */ 410dc90cad9SJulian Elischer static ng_ID_t 4114cf49a43SJulian Elischer ng_decodeidname(const char *name) 4124cf49a43SJulian Elischer { 413dc90cad9SJulian Elischer ng_ID_t val; 4144cf49a43SJulian Elischer int k, len; 4154cf49a43SJulian Elischer 4164cf49a43SJulian Elischer /* Basic checks */ 4174cf49a43SJulian Elischer for (len = 0; name[len] != '\0'; len++) { 4184cf49a43SJulian Elischer const char ch = name[len]; 4194cf49a43SJulian Elischer 4204cf49a43SJulian Elischer if (len == 0) { 4214cf49a43SJulian Elischer if (ch != '[') 4224cf49a43SJulian Elischer return (NULL); 4234cf49a43SJulian Elischer } else if (name[len + 1] == '\0') { 4244cf49a43SJulian Elischer if (ch != ']') 4254cf49a43SJulian Elischer return (NULL); 4264cf49a43SJulian Elischer } else if (!((ch >= '0' && ch <= '9') 4274cf49a43SJulian Elischer || (ch >= 'a' && ch <= 'f') 4284cf49a43SJulian Elischer || (ch >= 'A' && ch <= 'F'))) 4294cf49a43SJulian Elischer return (NULL); 4304cf49a43SJulian Elischer } 4314cf49a43SJulian Elischer if (len < 3 || len > (sizeof(val) * 2) + 2 || name[1] == '0') 4324cf49a43SJulian Elischer return (NULL); 4334cf49a43SJulian Elischer 4344cf49a43SJulian Elischer /* Convert number to binary */ 4354cf49a43SJulian Elischer for (val = 0, k = 1; k < len - 1; k++) { 4364cf49a43SJulian Elischer const char ch = name[k]; 4374cf49a43SJulian Elischer 4384cf49a43SJulian Elischer if (ch <= '9') 4394cf49a43SJulian Elischer val = (val << 4) | ((ch - '0') & 0xf); 4404cf49a43SJulian Elischer else 4414cf49a43SJulian Elischer val = (val << 4) | (((ch & 0xdf) - 'A' + 10) & 0xf); 4424cf49a43SJulian Elischer } 443dc90cad9SJulian Elischer return (val); 4444cf49a43SJulian Elischer } 4454cf49a43SJulian Elischer 4464cf49a43SJulian Elischer /* 4474cf49a43SJulian Elischer * Remove a name from a node. This should only be called 4484cf49a43SJulian Elischer * when shutting down and removing the node. 4494cf49a43SJulian Elischer */ 4504cf49a43SJulian Elischer void 4514cf49a43SJulian Elischer ng_unname(node_p node) 4524cf49a43SJulian Elischer { 4534cf49a43SJulian Elischer if (node->name) { 4544cf49a43SJulian Elischer FREE(node->name, M_NETGRAPH); 4554cf49a43SJulian Elischer node->name = NULL; 4564cf49a43SJulian Elischer ng_unref(node); 4574cf49a43SJulian Elischer } 4584cf49a43SJulian Elischer } 4594cf49a43SJulian Elischer 4604cf49a43SJulian Elischer /************************************************************************ 4614cf49a43SJulian Elischer Hook routines 4624cf49a43SJulian Elischer 4634cf49a43SJulian Elischer Names are not optional. Hooks are always connected, except for a 4644cf49a43SJulian Elischer brief moment within these routines. 4654cf49a43SJulian Elischer 4664cf49a43SJulian Elischer ************************************************************************/ 4674cf49a43SJulian Elischer 4684cf49a43SJulian Elischer /* 4694cf49a43SJulian Elischer * Remove a hook reference 4704cf49a43SJulian Elischer */ 4714cf49a43SJulian Elischer static void 4724cf49a43SJulian Elischer ng_unref_hook(hook_p hook) 4734cf49a43SJulian Elischer { 4744cf49a43SJulian Elischer if (--hook->refs == 0) 4754cf49a43SJulian Elischer FREE(hook, M_NETGRAPH); 4764cf49a43SJulian Elischer } 4774cf49a43SJulian Elischer 4784cf49a43SJulian Elischer /* 4794cf49a43SJulian Elischer * Add an unconnected hook to a node. Only used internally. 4804cf49a43SJulian Elischer */ 4814cf49a43SJulian Elischer static int 4824cf49a43SJulian Elischer ng_add_hook(node_p node, const char *name, hook_p *hookp) 4834cf49a43SJulian Elischer { 4844cf49a43SJulian Elischer hook_p hook; 4854cf49a43SJulian Elischer int error = 0; 4864cf49a43SJulian Elischer 4874cf49a43SJulian Elischer /* Check that the given name is good */ 4884cf49a43SJulian Elischer if (name == NULL) { 4894cf49a43SJulian Elischer TRAP_ERROR; 4904cf49a43SJulian Elischer return (EINVAL); 4914cf49a43SJulian Elischer } 4924cf49a43SJulian Elischer LIST_FOREACH(hook, &node->hooks, hooks) { 4934cf49a43SJulian Elischer if (strcmp(hook->name, name) == 0) { 4944cf49a43SJulian Elischer TRAP_ERROR; 4954cf49a43SJulian Elischer return (EEXIST); 4964cf49a43SJulian Elischer } 4974cf49a43SJulian Elischer } 4984cf49a43SJulian Elischer 4994cf49a43SJulian Elischer /* Allocate the hook and link it up */ 5004cf49a43SJulian Elischer MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_WAITOK); 5014cf49a43SJulian Elischer if (hook == NULL) { 5024cf49a43SJulian Elischer TRAP_ERROR; 5034cf49a43SJulian Elischer return (ENOMEM); 5044cf49a43SJulian Elischer } 5054cf49a43SJulian Elischer bzero(hook, sizeof(*hook)); 5064cf49a43SJulian Elischer hook->refs = 1; 5074cf49a43SJulian Elischer hook->flags = HK_INVALID; 5084cf49a43SJulian Elischer hook->node = node; 5094cf49a43SJulian Elischer node->refs++; /* each hook counts as a reference */ 5104cf49a43SJulian Elischer 5114cf49a43SJulian Elischer /* Check if the node type code has something to say about it */ 5124cf49a43SJulian Elischer if (node->type->newhook != NULL) 5134cf49a43SJulian Elischer if ((error = (*node->type->newhook)(node, hook, name)) != 0) 5144cf49a43SJulian Elischer goto fail; 5154cf49a43SJulian Elischer 5164cf49a43SJulian Elischer /* 5174cf49a43SJulian Elischer * The 'type' agrees so far, so go ahead and link it in. 5184cf49a43SJulian Elischer * We'll ask again later when we actually connect the hooks. 5194cf49a43SJulian Elischer */ 5204cf49a43SJulian Elischer LIST_INSERT_HEAD(&node->hooks, hook, hooks); 5214cf49a43SJulian Elischer node->numhooks++; 5224cf49a43SJulian Elischer 5234cf49a43SJulian Elischer /* Set hook name */ 5244cf49a43SJulian Elischer MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK); 5254cf49a43SJulian Elischer if (hook->name == NULL) { 5264cf49a43SJulian Elischer error = ENOMEM; 5274cf49a43SJulian Elischer LIST_REMOVE(hook, hooks); 5284cf49a43SJulian Elischer node->numhooks--; 5294cf49a43SJulian Elischer fail: 5304cf49a43SJulian Elischer hook->node = NULL; 5314cf49a43SJulian Elischer ng_unref(node); 5324cf49a43SJulian Elischer ng_unref_hook(hook); /* this frees the hook */ 5334cf49a43SJulian Elischer return (error); 5344cf49a43SJulian Elischer } 5354cf49a43SJulian Elischer strcpy(hook->name, name); 5364cf49a43SJulian Elischer if (hookp) 5374cf49a43SJulian Elischer *hookp = hook; 5384cf49a43SJulian Elischer return (error); 5394cf49a43SJulian Elischer } 5404cf49a43SJulian Elischer 5414cf49a43SJulian Elischer /* 5424cf49a43SJulian Elischer * Connect a pair of hooks. Only used internally. 5434cf49a43SJulian Elischer */ 5444cf49a43SJulian Elischer static int 5454cf49a43SJulian Elischer ng_connect(hook_p hook1, hook_p hook2) 5464cf49a43SJulian Elischer { 5474cf49a43SJulian Elischer int error; 5484cf49a43SJulian Elischer 5494cf49a43SJulian Elischer hook1->peer = hook2; 5504cf49a43SJulian Elischer hook2->peer = hook1; 5514cf49a43SJulian Elischer 5524cf49a43SJulian Elischer /* Give each node the opportunity to veto the impending connection */ 5534cf49a43SJulian Elischer if (hook1->node->type->connect) { 5544cf49a43SJulian Elischer if ((error = (*hook1->node->type->connect) (hook1))) { 5554cf49a43SJulian Elischer ng_destroy_hook(hook1); /* also zaps hook2 */ 5564cf49a43SJulian Elischer return (error); 5574cf49a43SJulian Elischer } 5584cf49a43SJulian Elischer } 5594cf49a43SJulian Elischer if (hook2->node->type->connect) { 5604cf49a43SJulian Elischer if ((error = (*hook2->node->type->connect) (hook2))) { 5614cf49a43SJulian Elischer ng_destroy_hook(hook2); /* also zaps hook1 */ 5624cf49a43SJulian Elischer return (error); 5634cf49a43SJulian Elischer } 5644cf49a43SJulian Elischer } 5654cf49a43SJulian Elischer hook1->flags &= ~HK_INVALID; 5664cf49a43SJulian Elischer hook2->flags &= ~HK_INVALID; 5674cf49a43SJulian Elischer return (0); 5684cf49a43SJulian Elischer } 5694cf49a43SJulian Elischer 5704cf49a43SJulian Elischer /* 5714cf49a43SJulian Elischer * Destroy a hook 5724cf49a43SJulian Elischer * 5734cf49a43SJulian Elischer * As hooks are always attached, this really destroys two hooks. 5744cf49a43SJulian Elischer * The one given, and the one attached to it. Disconnect the hooks 5754cf49a43SJulian Elischer * from each other first. 5764cf49a43SJulian Elischer */ 5774cf49a43SJulian Elischer void 5784cf49a43SJulian Elischer ng_destroy_hook(hook_p hook) 5794cf49a43SJulian Elischer { 5804cf49a43SJulian Elischer hook_p peer = hook->peer; 5814cf49a43SJulian Elischer 5824cf49a43SJulian Elischer hook->flags |= HK_INVALID; /* as soon as possible */ 5834cf49a43SJulian Elischer if (peer) { 5844cf49a43SJulian Elischer peer->flags |= HK_INVALID; /* as soon as possible */ 5854cf49a43SJulian Elischer hook->peer = NULL; 5864cf49a43SJulian Elischer peer->peer = NULL; 5874cf49a43SJulian Elischer ng_disconnect_hook(peer); 5884cf49a43SJulian Elischer } 5894cf49a43SJulian Elischer ng_disconnect_hook(hook); 5904cf49a43SJulian Elischer } 5914cf49a43SJulian Elischer 5924cf49a43SJulian Elischer /* 5934cf49a43SJulian Elischer * Notify the node of the hook's demise. This may result in more actions 5944cf49a43SJulian Elischer * (e.g. shutdown) but we don't do that ourselves and don't know what 5954cf49a43SJulian Elischer * happens there. If there is no appropriate handler, then just remove it 5964cf49a43SJulian Elischer * (and decrement the reference count of it's node which in turn might 5974cf49a43SJulian Elischer * make something happen). 5984cf49a43SJulian Elischer */ 5994cf49a43SJulian Elischer static void 6004cf49a43SJulian Elischer ng_disconnect_hook(hook_p hook) 6014cf49a43SJulian Elischer { 6024cf49a43SJulian Elischer node_p node = hook->node; 6034cf49a43SJulian Elischer 6044cf49a43SJulian Elischer /* 6054cf49a43SJulian Elischer * Remove the hook from the node's list to avoid possible recursion 6064cf49a43SJulian Elischer * in case the disconnection results in node shutdown. 6074cf49a43SJulian Elischer */ 6084cf49a43SJulian Elischer LIST_REMOVE(hook, hooks); 6094cf49a43SJulian Elischer node->numhooks--; 6104cf49a43SJulian Elischer if (node->type->disconnect) { 6114cf49a43SJulian Elischer /* 6124cf49a43SJulian Elischer * The type handler may elect to destroy the peer so don't 6134cf49a43SJulian Elischer * trust its existance after this point. 6144cf49a43SJulian Elischer */ 6154cf49a43SJulian Elischer (*node->type->disconnect) (hook); 6164cf49a43SJulian Elischer } 6174cf49a43SJulian Elischer ng_unref(node); /* might be the last reference */ 6184cf49a43SJulian Elischer if (hook->name) 6194cf49a43SJulian Elischer FREE(hook->name, M_NETGRAPH); 6204cf49a43SJulian Elischer hook->node = NULL; /* may still be referenced elsewhere */ 6214cf49a43SJulian Elischer ng_unref_hook(hook); 6224cf49a43SJulian Elischer } 6234cf49a43SJulian Elischer 6244cf49a43SJulian Elischer /* 6254cf49a43SJulian Elischer * Take two hooks on a node and merge the connection so that the given node 6264cf49a43SJulian Elischer * is effectively bypassed. 6274cf49a43SJulian Elischer */ 6284cf49a43SJulian Elischer int 6294cf49a43SJulian Elischer ng_bypass(hook_p hook1, hook_p hook2) 6304cf49a43SJulian Elischer { 6314cf49a43SJulian Elischer if (hook1->node != hook2->node) 6324cf49a43SJulian Elischer return (EINVAL); 6334cf49a43SJulian Elischer hook1->peer->peer = hook2->peer; 6344cf49a43SJulian Elischer hook2->peer->peer = hook1->peer; 6354cf49a43SJulian Elischer 6364cf49a43SJulian Elischer /* XXX If we ever cache methods on hooks update them as well */ 6374cf49a43SJulian Elischer hook1->peer = NULL; 6384cf49a43SJulian Elischer hook2->peer = NULL; 6394cf49a43SJulian Elischer ng_destroy_hook(hook1); 6404cf49a43SJulian Elischer ng_destroy_hook(hook2); 6414cf49a43SJulian Elischer return (0); 6424cf49a43SJulian Elischer } 6434cf49a43SJulian Elischer 6444cf49a43SJulian Elischer /* 6454cf49a43SJulian Elischer * Install a new netgraph type 6464cf49a43SJulian Elischer */ 6474cf49a43SJulian Elischer int 6484cf49a43SJulian Elischer ng_newtype(struct ng_type *tp) 6494cf49a43SJulian Elischer { 6504cf49a43SJulian Elischer const size_t namelen = strlen(tp->name); 6514cf49a43SJulian Elischer 6524cf49a43SJulian Elischer /* Check version and type name fields */ 6534cf49a43SJulian Elischer if (tp->version != NG_VERSION || namelen == 0 || namelen > NG_TYPELEN) { 6544cf49a43SJulian Elischer TRAP_ERROR; 6554cf49a43SJulian Elischer return (EINVAL); 6564cf49a43SJulian Elischer } 6574cf49a43SJulian Elischer 6584cf49a43SJulian Elischer /* Check for name collision */ 6594cf49a43SJulian Elischer if (ng_findtype(tp->name) != NULL) { 6604cf49a43SJulian Elischer TRAP_ERROR; 6614cf49a43SJulian Elischer return (EEXIST); 6624cf49a43SJulian Elischer } 6634cf49a43SJulian Elischer 6644cf49a43SJulian Elischer /* Link in new type */ 6654cf49a43SJulian Elischer LIST_INSERT_HEAD(&typelist, tp, types); 6664cf49a43SJulian Elischer tp->refs = 0; 6674cf49a43SJulian Elischer return (0); 6684cf49a43SJulian Elischer } 6694cf49a43SJulian Elischer 6704cf49a43SJulian Elischer /* 6714cf49a43SJulian Elischer * Look for a type of the name given 6724cf49a43SJulian Elischer */ 6734cf49a43SJulian Elischer struct ng_type * 6744cf49a43SJulian Elischer ng_findtype(const char *typename) 6754cf49a43SJulian Elischer { 6764cf49a43SJulian Elischer struct ng_type *type; 6774cf49a43SJulian Elischer 6784cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) { 6794cf49a43SJulian Elischer if (strcmp(type->name, typename) == 0) 6804cf49a43SJulian Elischer break; 6814cf49a43SJulian Elischer } 6824cf49a43SJulian Elischer return (type); 6834cf49a43SJulian Elischer } 6844cf49a43SJulian Elischer 6854cf49a43SJulian Elischer 6864cf49a43SJulian Elischer /************************************************************************ 6874cf49a43SJulian Elischer Composite routines 6884cf49a43SJulian Elischer ************************************************************************/ 6894cf49a43SJulian Elischer 6904cf49a43SJulian Elischer /* 6914cf49a43SJulian Elischer * Make a peer and connect. The order is arranged to minimise 6924cf49a43SJulian Elischer * the work needed to back out in case of error. 6934cf49a43SJulian Elischer */ 6944cf49a43SJulian Elischer int 6954cf49a43SJulian Elischer ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 6964cf49a43SJulian Elischer { 6974cf49a43SJulian Elischer node_p node2; 6984cf49a43SJulian Elischer hook_p hook; 6994cf49a43SJulian Elischer hook_p hook2; 7004cf49a43SJulian Elischer int error; 7014cf49a43SJulian Elischer 7024cf49a43SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) 7034cf49a43SJulian Elischer return (error); 7044cf49a43SJulian Elischer if ((error = ng_make_node(type, &node2))) { 7054cf49a43SJulian Elischer ng_destroy_hook(hook); 7064cf49a43SJulian Elischer return (error); 7074cf49a43SJulian Elischer } 7084cf49a43SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 7094cf49a43SJulian Elischer ng_rmnode(node2); 7104cf49a43SJulian Elischer ng_destroy_hook(hook); 7114cf49a43SJulian Elischer return (error); 7124cf49a43SJulian Elischer } 7134cf49a43SJulian Elischer 7144cf49a43SJulian Elischer /* 7154cf49a43SJulian Elischer * Actually link the two hooks together.. on failure they are 7164cf49a43SJulian Elischer * destroyed so we don't have to do that here. 7174cf49a43SJulian Elischer */ 7184cf49a43SJulian Elischer if ((error = ng_connect(hook, hook2))) 7194cf49a43SJulian Elischer ng_rmnode(node2); 7204cf49a43SJulian Elischer return (error); 7214cf49a43SJulian Elischer } 7224cf49a43SJulian Elischer 7234cf49a43SJulian Elischer /* 7244cf49a43SJulian Elischer * Connect two nodes using the specified hooks 7254cf49a43SJulian Elischer */ 7264cf49a43SJulian Elischer int 7274cf49a43SJulian Elischer ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2) 7284cf49a43SJulian Elischer { 7294cf49a43SJulian Elischer int error; 7304cf49a43SJulian Elischer hook_p hook; 7314cf49a43SJulian Elischer hook_p hook2; 7324cf49a43SJulian Elischer 7334cf49a43SJulian Elischer if ((error = ng_add_hook(node, name, &hook))) 7344cf49a43SJulian Elischer return (error); 7354cf49a43SJulian Elischer if ((error = ng_add_hook(node2, name2, &hook2))) { 7364cf49a43SJulian Elischer ng_destroy_hook(hook); 7374cf49a43SJulian Elischer return (error); 7384cf49a43SJulian Elischer } 7394cf49a43SJulian Elischer return (ng_connect(hook, hook2)); 7404cf49a43SJulian Elischer } 7414cf49a43SJulian Elischer 7424cf49a43SJulian Elischer /* 7434cf49a43SJulian Elischer * Parse and verify a string of the form: <NODE:><PATH> 7444cf49a43SJulian Elischer * 7454cf49a43SJulian Elischer * Such a string can refer to a specific node or a specific hook 7464cf49a43SJulian Elischer * on a specific node, depending on how you look at it. In the 7474cf49a43SJulian Elischer * latter case, the PATH component must not end in a dot. 7484cf49a43SJulian Elischer * 7494cf49a43SJulian Elischer * Both <NODE:> and <PATH> are optional. The <PATH> is a string 7504cf49a43SJulian Elischer * of hook names separated by dots. This breaks out the original 7514cf49a43SJulian Elischer * string, setting *nodep to "NODE" (or NULL if none) and *pathp 7524cf49a43SJulian Elischer * to "PATH" (or NULL if degenerate). Also, *hookp will point to 7534cf49a43SJulian Elischer * the final hook component of <PATH>, if any, otherwise NULL. 7544cf49a43SJulian Elischer * 7554cf49a43SJulian Elischer * This returns -1 if the path is malformed. The char ** are optional. 7564cf49a43SJulian Elischer */ 7574cf49a43SJulian Elischer 7584cf49a43SJulian Elischer int 7594cf49a43SJulian Elischer ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 7604cf49a43SJulian Elischer { 7614cf49a43SJulian Elischer char *node, *path, *hook; 7624cf49a43SJulian Elischer int k; 7634cf49a43SJulian Elischer 7644cf49a43SJulian Elischer /* 7654cf49a43SJulian Elischer * Extract absolute NODE, if any 7664cf49a43SJulian Elischer */ 7674cf49a43SJulian Elischer for (path = addr; *path && *path != ':'; path++); 7684cf49a43SJulian Elischer if (*path) { 7694cf49a43SJulian Elischer node = addr; /* Here's the NODE */ 7704cf49a43SJulian Elischer *path++ = '\0'; /* Here's the PATH */ 7714cf49a43SJulian Elischer 7724cf49a43SJulian Elischer /* Node name must not be empty */ 7734cf49a43SJulian Elischer if (!*node) 7744cf49a43SJulian Elischer return -1; 7754cf49a43SJulian Elischer 7764cf49a43SJulian Elischer /* A name of "." is OK; otherwise '.' not allowed */ 7774cf49a43SJulian Elischer if (strcmp(node, ".") != 0) { 7784cf49a43SJulian Elischer for (k = 0; node[k]; k++) 7794cf49a43SJulian Elischer if (node[k] == '.') 7804cf49a43SJulian Elischer return -1; 7814cf49a43SJulian Elischer } 7824cf49a43SJulian Elischer } else { 7834cf49a43SJulian Elischer node = NULL; /* No absolute NODE */ 7844cf49a43SJulian Elischer path = addr; /* Here's the PATH */ 7854cf49a43SJulian Elischer } 7864cf49a43SJulian Elischer 7874cf49a43SJulian Elischer /* Snoop for illegal characters in PATH */ 7884cf49a43SJulian Elischer for (k = 0; path[k]; k++) 7894cf49a43SJulian Elischer if (path[k] == ':') 7904cf49a43SJulian Elischer return -1; 7914cf49a43SJulian Elischer 7924cf49a43SJulian Elischer /* Check for no repeated dots in PATH */ 7934cf49a43SJulian Elischer for (k = 0; path[k]; k++) 7944cf49a43SJulian Elischer if (path[k] == '.' && path[k + 1] == '.') 7954cf49a43SJulian Elischer return -1; 7964cf49a43SJulian Elischer 7974cf49a43SJulian Elischer /* Remove extra (degenerate) dots from beginning or end of PATH */ 7984cf49a43SJulian Elischer if (path[0] == '.') 7994cf49a43SJulian Elischer path++; 8004cf49a43SJulian Elischer if (*path && path[strlen(path) - 1] == '.') 8014cf49a43SJulian Elischer path[strlen(path) - 1] = 0; 8024cf49a43SJulian Elischer 8034cf49a43SJulian Elischer /* If PATH has a dot, then we're not talking about a hook */ 8044cf49a43SJulian Elischer if (*path) { 8054cf49a43SJulian Elischer for (hook = path, k = 0; path[k]; k++) 8064cf49a43SJulian Elischer if (path[k] == '.') { 8074cf49a43SJulian Elischer hook = NULL; 8084cf49a43SJulian Elischer break; 8094cf49a43SJulian Elischer } 8104cf49a43SJulian Elischer } else 8114cf49a43SJulian Elischer path = hook = NULL; 8124cf49a43SJulian Elischer 8134cf49a43SJulian Elischer /* Done */ 8144cf49a43SJulian Elischer if (nodep) 8154cf49a43SJulian Elischer *nodep = node; 8164cf49a43SJulian Elischer if (pathp) 8174cf49a43SJulian Elischer *pathp = path; 8184cf49a43SJulian Elischer if (hookp) 8194cf49a43SJulian Elischer *hookp = hook; 8204cf49a43SJulian Elischer return (0); 8214cf49a43SJulian Elischer } 8224cf49a43SJulian Elischer 8234cf49a43SJulian Elischer /* 8244cf49a43SJulian Elischer * Given a path, which may be absolute or relative, and a starting node, 8254cf49a43SJulian Elischer * return the destination node. Compute the "return address" if desired. 8264cf49a43SJulian Elischer */ 8274cf49a43SJulian Elischer int 8284cf49a43SJulian Elischer ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp) 8294cf49a43SJulian Elischer { 8304cf49a43SJulian Elischer const node_p start = here; 8314cf49a43SJulian Elischer char fullpath[NG_PATHLEN + 1]; 8324cf49a43SJulian Elischer char *nodename, *path, pbuf[2]; 8334cf49a43SJulian Elischer node_p node; 8344cf49a43SJulian Elischer char *cp; 8354cf49a43SJulian Elischer 8364cf49a43SJulian Elischer /* Initialize */ 8374cf49a43SJulian Elischer if (rtnp) 8384cf49a43SJulian Elischer *rtnp = NULL; 8394cf49a43SJulian Elischer if (destp == NULL) 8404cf49a43SJulian Elischer return EINVAL; 8414cf49a43SJulian Elischer *destp = NULL; 8424cf49a43SJulian Elischer 8434cf49a43SJulian Elischer /* Make a writable copy of address for ng_path_parse() */ 8444cf49a43SJulian Elischer strncpy(fullpath, address, sizeof(fullpath) - 1); 8454cf49a43SJulian Elischer fullpath[sizeof(fullpath) - 1] = '\0'; 8464cf49a43SJulian Elischer 8474cf49a43SJulian Elischer /* Parse out node and sequence of hooks */ 8484cf49a43SJulian Elischer if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 8494cf49a43SJulian Elischer TRAP_ERROR; 8504cf49a43SJulian Elischer return EINVAL; 8514cf49a43SJulian Elischer } 8524cf49a43SJulian Elischer if (path == NULL) { 8534cf49a43SJulian Elischer pbuf[0] = '.'; /* Needs to be writable */ 8544cf49a43SJulian Elischer pbuf[1] = '\0'; 8554cf49a43SJulian Elischer path = pbuf; 8564cf49a43SJulian Elischer } 8574cf49a43SJulian Elischer 8584cf49a43SJulian Elischer /* For an absolute address, jump to the starting node */ 8594cf49a43SJulian Elischer if (nodename) { 8604cf49a43SJulian Elischer node = ng_findname(here, nodename); 8614cf49a43SJulian Elischer if (node == NULL) { 8624cf49a43SJulian Elischer TRAP_ERROR; 8634cf49a43SJulian Elischer return (ENOENT); 8644cf49a43SJulian Elischer } 8654cf49a43SJulian Elischer } else 8664cf49a43SJulian Elischer node = here; 8674cf49a43SJulian Elischer 8684cf49a43SJulian Elischer /* Now follow the sequence of hooks */ 8694cf49a43SJulian Elischer for (cp = path; node != NULL && *cp != '\0'; ) { 8704cf49a43SJulian Elischer hook_p hook; 8714cf49a43SJulian Elischer char *segment; 8724cf49a43SJulian Elischer 8734cf49a43SJulian Elischer /* 8744cf49a43SJulian Elischer * Break out the next path segment. Replace the dot we just 8754cf49a43SJulian Elischer * found with a NUL; "cp" points to the next segment (or the 8764cf49a43SJulian Elischer * NUL at the end). 8774cf49a43SJulian Elischer */ 8784cf49a43SJulian Elischer for (segment = cp; *cp != '\0'; cp++) { 8794cf49a43SJulian Elischer if (*cp == '.') { 8804cf49a43SJulian Elischer *cp++ = '\0'; 8814cf49a43SJulian Elischer break; 8824cf49a43SJulian Elischer } 8834cf49a43SJulian Elischer } 8844cf49a43SJulian Elischer 8854cf49a43SJulian Elischer /* Empty segment */ 8864cf49a43SJulian Elischer if (*segment == '\0') 8874cf49a43SJulian Elischer continue; 8884cf49a43SJulian Elischer 8894cf49a43SJulian Elischer /* We have a segment, so look for a hook by that name */ 8904cf49a43SJulian Elischer LIST_FOREACH(hook, &node->hooks, hooks) { 8914cf49a43SJulian Elischer if (hook->name && strcmp(hook->name, segment) == 0) 8924cf49a43SJulian Elischer break; 8934cf49a43SJulian Elischer } 8944cf49a43SJulian Elischer 8954cf49a43SJulian Elischer /* Can't get there from here... */ 8964cf49a43SJulian Elischer if (hook == NULL 8974cf49a43SJulian Elischer || hook->peer == NULL 8984cf49a43SJulian Elischer || (hook->flags & HK_INVALID) != 0) { 8994cf49a43SJulian Elischer TRAP_ERROR; 9004cf49a43SJulian Elischer return (ENOENT); 9014cf49a43SJulian Elischer } 9024cf49a43SJulian Elischer 9034cf49a43SJulian Elischer /* Hop on over to the next node */ 9044cf49a43SJulian Elischer node = hook->peer->node; 9054cf49a43SJulian Elischer } 9064cf49a43SJulian Elischer 9074cf49a43SJulian Elischer /* If node somehow missing, fail here (probably this is not needed) */ 9084cf49a43SJulian Elischer if (node == NULL) { 9094cf49a43SJulian Elischer TRAP_ERROR; 9104cf49a43SJulian Elischer return (ENXIO); 9114cf49a43SJulian Elischer } 9124cf49a43SJulian Elischer 9134cf49a43SJulian Elischer /* Now compute return address, i.e., the path to the sender */ 9144cf49a43SJulian Elischer if (rtnp != NULL) { 9154cf49a43SJulian Elischer MALLOC(*rtnp, char *, NG_NODELEN + 2, M_NETGRAPH, M_WAITOK); 9164cf49a43SJulian Elischer if (*rtnp == NULL) { 9174cf49a43SJulian Elischer TRAP_ERROR; 9184cf49a43SJulian Elischer return (ENOMEM); 9194cf49a43SJulian Elischer } 9204cf49a43SJulian Elischer if (start->name != NULL) 9214cf49a43SJulian Elischer sprintf(*rtnp, "%s:", start->name); 9224cf49a43SJulian Elischer else 923dc90cad9SJulian Elischer sprintf(*rtnp, "[%x]:", ng_node2ID(start)); 9244cf49a43SJulian Elischer } 9254cf49a43SJulian Elischer 9264cf49a43SJulian Elischer /* Done */ 9274cf49a43SJulian Elischer *destp = node; 9284cf49a43SJulian Elischer return (0); 9294cf49a43SJulian Elischer } 9304cf49a43SJulian Elischer 9314cf49a43SJulian Elischer /* 9324cf49a43SJulian Elischer * Call the appropriate message handler for the object. 9334cf49a43SJulian Elischer * It is up to the message handler to free the message. 9344cf49a43SJulian Elischer * If it's a generic message, handle it generically, otherwise 9354cf49a43SJulian Elischer * call the type's message handler (if it exists) 9364cf49a43SJulian Elischer */ 9374cf49a43SJulian Elischer 9384cf49a43SJulian Elischer #define CALL_MSG_HANDLER(error, node, msg, retaddr, resp) \ 9394cf49a43SJulian Elischer do { \ 9404cf49a43SJulian Elischer if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \ 9414cf49a43SJulian Elischer (error) = ng_generic_msg((node), (msg), \ 9424cf49a43SJulian Elischer (retaddr), (resp)); \ 9434cf49a43SJulian Elischer } else { \ 9444cf49a43SJulian Elischer if ((node)->type->rcvmsg != NULL) { \ 9454cf49a43SJulian Elischer (error) = (*(node)->type->rcvmsg)((node), \ 9464cf49a43SJulian Elischer (msg), (retaddr), (resp)); \ 9474cf49a43SJulian Elischer } else { \ 9484cf49a43SJulian Elischer TRAP_ERROR; \ 9494cf49a43SJulian Elischer FREE((msg), M_NETGRAPH); \ 9504cf49a43SJulian Elischer (error) = EINVAL; \ 9514cf49a43SJulian Elischer } \ 9524cf49a43SJulian Elischer } \ 9534cf49a43SJulian Elischer } while (0) 9544cf49a43SJulian Elischer 9554cf49a43SJulian Elischer 9564cf49a43SJulian Elischer /* 9574cf49a43SJulian Elischer * Send a control message to a node 9584cf49a43SJulian Elischer */ 9594cf49a43SJulian Elischer int 9604cf49a43SJulian Elischer ng_send_msg(node_p here, struct ng_mesg *msg, const char *address, 9614cf49a43SJulian Elischer struct ng_mesg **rptr) 9624cf49a43SJulian Elischer { 9634cf49a43SJulian Elischer node_p dest = NULL; 9644cf49a43SJulian Elischer char *retaddr = NULL; 9654cf49a43SJulian Elischer int error; 9664cf49a43SJulian Elischer 9674cf49a43SJulian Elischer /* Find the target node */ 9684cf49a43SJulian Elischer error = ng_path2node(here, address, &dest, &retaddr); 9694cf49a43SJulian Elischer if (error) { 9704cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 9714cf49a43SJulian Elischer return error; 9724cf49a43SJulian Elischer } 9734cf49a43SJulian Elischer 9744cf49a43SJulian Elischer /* Make sure the resp field is null before we start */ 9754cf49a43SJulian Elischer if (rptr != NULL) 9764cf49a43SJulian Elischer *rptr = NULL; 9774cf49a43SJulian Elischer 9784cf49a43SJulian Elischer CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr); 9794cf49a43SJulian Elischer 9804cf49a43SJulian Elischer /* Make sure that if there is a response, it has the RESP bit set */ 9814cf49a43SJulian Elischer if ((error == 0) && rptr && *rptr) 9824cf49a43SJulian Elischer (*rptr)->header.flags |= NGF_RESP; 9834cf49a43SJulian Elischer 9844cf49a43SJulian Elischer /* 9854cf49a43SJulian Elischer * If we had a return address it is up to us to free it. They should 9864cf49a43SJulian Elischer * have taken a copy if they needed to make a delayed response. 9874cf49a43SJulian Elischer */ 9884cf49a43SJulian Elischer if (retaddr) 9894cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 9904cf49a43SJulian Elischer return (error); 9914cf49a43SJulian Elischer } 9924cf49a43SJulian Elischer 9934cf49a43SJulian Elischer /* 9944cf49a43SJulian Elischer * Implement the 'generic' control messages 9954cf49a43SJulian Elischer */ 9964cf49a43SJulian Elischer static int 9974cf49a43SJulian Elischer ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr, 9984cf49a43SJulian Elischer struct ng_mesg **resp) 9994cf49a43SJulian Elischer { 10004cf49a43SJulian Elischer int error = 0; 10014cf49a43SJulian Elischer 10024cf49a43SJulian Elischer if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 10034cf49a43SJulian Elischer TRAP_ERROR; 10044cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 10054cf49a43SJulian Elischer return (EINVAL); 10064cf49a43SJulian Elischer } 10074cf49a43SJulian Elischer switch (msg->header.cmd) { 10084cf49a43SJulian Elischer case NGM_SHUTDOWN: 10094cf49a43SJulian Elischer ng_rmnode(here); 10104cf49a43SJulian Elischer break; 10114cf49a43SJulian Elischer case NGM_MKPEER: 10124cf49a43SJulian Elischer { 10134cf49a43SJulian Elischer struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 10144cf49a43SJulian Elischer 10154cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*mkp)) { 10164cf49a43SJulian Elischer TRAP_ERROR; 10174cf49a43SJulian Elischer return (EINVAL); 10184cf49a43SJulian Elischer } 10194cf49a43SJulian Elischer mkp->type[sizeof(mkp->type) - 1] = '\0'; 10204cf49a43SJulian Elischer mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 10214cf49a43SJulian Elischer mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 10224cf49a43SJulian Elischer error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 10234cf49a43SJulian Elischer break; 10244cf49a43SJulian Elischer } 10254cf49a43SJulian Elischer case NGM_CONNECT: 10264cf49a43SJulian Elischer { 10274cf49a43SJulian Elischer struct ngm_connect *const con = 10284cf49a43SJulian Elischer (struct ngm_connect *) msg->data; 10294cf49a43SJulian Elischer node_p node2; 10304cf49a43SJulian Elischer 10314cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*con)) { 10324cf49a43SJulian Elischer TRAP_ERROR; 10334cf49a43SJulian Elischer return (EINVAL); 10344cf49a43SJulian Elischer } 10354cf49a43SJulian Elischer con->path[sizeof(con->path) - 1] = '\0'; 10364cf49a43SJulian Elischer con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 10374cf49a43SJulian Elischer con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 10384cf49a43SJulian Elischer error = ng_path2node(here, con->path, &node2, NULL); 10394cf49a43SJulian Elischer if (error) 10404cf49a43SJulian Elischer break; 10414cf49a43SJulian Elischer error = ng_con_nodes(here, con->ourhook, node2, con->peerhook); 10424cf49a43SJulian Elischer break; 10434cf49a43SJulian Elischer } 10444cf49a43SJulian Elischer case NGM_NAME: 10454cf49a43SJulian Elischer { 10464cf49a43SJulian Elischer struct ngm_name *const nam = (struct ngm_name *) msg->data; 10474cf49a43SJulian Elischer 10484cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*nam)) { 10494cf49a43SJulian Elischer TRAP_ERROR; 10504cf49a43SJulian Elischer return (EINVAL); 10514cf49a43SJulian Elischer } 10524cf49a43SJulian Elischer nam->name[sizeof(nam->name) - 1] = '\0'; 10534cf49a43SJulian Elischer error = ng_name_node(here, nam->name); 10544cf49a43SJulian Elischer break; 10554cf49a43SJulian Elischer } 10564cf49a43SJulian Elischer case NGM_RMHOOK: 10574cf49a43SJulian Elischer { 10584cf49a43SJulian Elischer struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 10594cf49a43SJulian Elischer hook_p hook; 10604cf49a43SJulian Elischer 10614cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*rmh)) { 10624cf49a43SJulian Elischer TRAP_ERROR; 10634cf49a43SJulian Elischer return (EINVAL); 10644cf49a43SJulian Elischer } 10654cf49a43SJulian Elischer rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 10664cf49a43SJulian Elischer LIST_FOREACH(hook, &here->hooks, hooks) { 10674cf49a43SJulian Elischer if (hook->name && strcmp(hook->name, rmh->ourhook) == 0) 10684cf49a43SJulian Elischer break; 10694cf49a43SJulian Elischer } 10704cf49a43SJulian Elischer if (hook) 10714cf49a43SJulian Elischer ng_destroy_hook(hook); 10724cf49a43SJulian Elischer break; 10734cf49a43SJulian Elischer } 10744cf49a43SJulian Elischer case NGM_NODEINFO: 10754cf49a43SJulian Elischer { 10764cf49a43SJulian Elischer struct nodeinfo *ni; 10774cf49a43SJulian Elischer struct ng_mesg *rp; 10784cf49a43SJulian Elischer 10794cf49a43SJulian Elischer /* Get response struct */ 10804cf49a43SJulian Elischer if (resp == NULL) { 10814cf49a43SJulian Elischer error = EINVAL; 10824cf49a43SJulian Elischer break; 10834cf49a43SJulian Elischer } 10844cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT); 10854cf49a43SJulian Elischer if (rp == NULL) { 10864cf49a43SJulian Elischer error = ENOMEM; 10874cf49a43SJulian Elischer break; 10884cf49a43SJulian Elischer } 10894cf49a43SJulian Elischer 10904cf49a43SJulian Elischer /* Fill in node info */ 10914cf49a43SJulian Elischer ni = (struct nodeinfo *) rp->data; 10924cf49a43SJulian Elischer if (here->name != NULL) 10934cf49a43SJulian Elischer strncpy(ni->name, here->name, NG_NODELEN); 10944cf49a43SJulian Elischer strncpy(ni->type, here->type->name, NG_TYPELEN); 1095dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 10964cf49a43SJulian Elischer ni->hooks = here->numhooks; 10974cf49a43SJulian Elischer *resp = rp; 10984cf49a43SJulian Elischer break; 10994cf49a43SJulian Elischer } 11004cf49a43SJulian Elischer case NGM_LISTHOOKS: 11014cf49a43SJulian Elischer { 11024cf49a43SJulian Elischer const int nhooks = here->numhooks; 11034cf49a43SJulian Elischer struct hooklist *hl; 11044cf49a43SJulian Elischer struct nodeinfo *ni; 11054cf49a43SJulian Elischer struct ng_mesg *rp; 11064cf49a43SJulian Elischer hook_p hook; 11074cf49a43SJulian Elischer 11084cf49a43SJulian Elischer /* Get response struct */ 11094cf49a43SJulian Elischer if (resp == NULL) { 11104cf49a43SJulian Elischer error = EINVAL; 11114cf49a43SJulian Elischer break; 11124cf49a43SJulian Elischer } 11134cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*hl) 11144cf49a43SJulian Elischer + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 11154cf49a43SJulian Elischer if (rp == NULL) { 11164cf49a43SJulian Elischer error = ENOMEM; 11174cf49a43SJulian Elischer break; 11184cf49a43SJulian Elischer } 11194cf49a43SJulian Elischer hl = (struct hooklist *) rp->data; 11204cf49a43SJulian Elischer ni = &hl->nodeinfo; 11214cf49a43SJulian Elischer 11224cf49a43SJulian Elischer /* Fill in node info */ 11234cf49a43SJulian Elischer if (here->name) 11244cf49a43SJulian Elischer strncpy(ni->name, here->name, NG_NODELEN); 11254cf49a43SJulian Elischer strncpy(ni->type, here->type->name, NG_TYPELEN); 1126dc90cad9SJulian Elischer ni->id = ng_node2ID(here); 11274cf49a43SJulian Elischer 11284cf49a43SJulian Elischer /* Cycle through the linked list of hooks */ 11294cf49a43SJulian Elischer ni->hooks = 0; 11304cf49a43SJulian Elischer LIST_FOREACH(hook, &here->hooks, hooks) { 11314cf49a43SJulian Elischer struct linkinfo *const link = &hl->link[ni->hooks]; 11324cf49a43SJulian Elischer 11334cf49a43SJulian Elischer if (ni->hooks >= nhooks) { 11344cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 11354cf49a43SJulian Elischer __FUNCTION__, "hooks"); 11364cf49a43SJulian Elischer break; 11374cf49a43SJulian Elischer } 11384cf49a43SJulian Elischer if ((hook->flags & HK_INVALID) != 0) 11394cf49a43SJulian Elischer continue; 11404cf49a43SJulian Elischer strncpy(link->ourhook, hook->name, NG_HOOKLEN); 11414cf49a43SJulian Elischer strncpy(link->peerhook, hook->peer->name, NG_HOOKLEN); 11424cf49a43SJulian Elischer if (hook->peer->node->name != NULL) 11434cf49a43SJulian Elischer strncpy(link->nodeinfo.name, 11444cf49a43SJulian Elischer hook->peer->node->name, NG_NODELEN); 11454cf49a43SJulian Elischer strncpy(link->nodeinfo.type, 11464cf49a43SJulian Elischer hook->peer->node->type->name, NG_TYPELEN); 1147dc90cad9SJulian Elischer link->nodeinfo.id = ng_node2ID(hook->peer->node); 11484cf49a43SJulian Elischer link->nodeinfo.hooks = hook->peer->node->numhooks; 11494cf49a43SJulian Elischer ni->hooks++; 11504cf49a43SJulian Elischer } 11514cf49a43SJulian Elischer *resp = rp; 11524cf49a43SJulian Elischer break; 11534cf49a43SJulian Elischer } 11544cf49a43SJulian Elischer 11554cf49a43SJulian Elischer case NGM_LISTNAMES: 11564cf49a43SJulian Elischer case NGM_LISTNODES: 11574cf49a43SJulian Elischer { 11584cf49a43SJulian Elischer const int unnamed = (msg->header.cmd == NGM_LISTNODES); 11594cf49a43SJulian Elischer struct namelist *nl; 11604cf49a43SJulian Elischer struct ng_mesg *rp; 11614cf49a43SJulian Elischer node_p node; 11624cf49a43SJulian Elischer int num = 0; 11634cf49a43SJulian Elischer 11644cf49a43SJulian Elischer if (resp == NULL) { 11654cf49a43SJulian Elischer error = EINVAL; 11664cf49a43SJulian Elischer break; 11674cf49a43SJulian Elischer } 11684cf49a43SJulian Elischer 11694cf49a43SJulian Elischer /* Count number of nodes */ 11704cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 11714cf49a43SJulian Elischer if (unnamed || node->name != NULL) 11724cf49a43SJulian Elischer num++; 11734cf49a43SJulian Elischer } 11744cf49a43SJulian Elischer 11754cf49a43SJulian Elischer /* Get response struct */ 11764cf49a43SJulian Elischer if (resp == NULL) { 11774cf49a43SJulian Elischer error = EINVAL; 11784cf49a43SJulian Elischer break; 11794cf49a43SJulian Elischer } 11804cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*nl) 11814cf49a43SJulian Elischer + (num * sizeof(struct nodeinfo)), M_NOWAIT); 11824cf49a43SJulian Elischer if (rp == NULL) { 11834cf49a43SJulian Elischer error = ENOMEM; 11844cf49a43SJulian Elischer break; 11854cf49a43SJulian Elischer } 11864cf49a43SJulian Elischer nl = (struct namelist *) rp->data; 11874cf49a43SJulian Elischer 11884cf49a43SJulian Elischer /* Cycle through the linked list of nodes */ 11894cf49a43SJulian Elischer nl->numnames = 0; 11904cf49a43SJulian Elischer LIST_FOREACH(node, &nodelist, nodes) { 11914cf49a43SJulian Elischer struct nodeinfo *const np = &nl->nodeinfo[nl->numnames]; 11924cf49a43SJulian Elischer 11934cf49a43SJulian Elischer if (nl->numnames >= num) { 11944cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 11954cf49a43SJulian Elischer __FUNCTION__, "nodes"); 11964cf49a43SJulian Elischer break; 11974cf49a43SJulian Elischer } 11984cf49a43SJulian Elischer if ((node->flags & NG_INVALID) != 0) 11994cf49a43SJulian Elischer continue; 12004cf49a43SJulian Elischer if (!unnamed && node->name == NULL) 12014cf49a43SJulian Elischer continue; 12024cf49a43SJulian Elischer if (node->name != NULL) 12034cf49a43SJulian Elischer strncpy(np->name, node->name, NG_NODELEN); 12044cf49a43SJulian Elischer strncpy(np->type, node->type->name, NG_TYPELEN); 1205dc90cad9SJulian Elischer np->id = ng_node2ID(node); 12064cf49a43SJulian Elischer np->hooks = node->numhooks; 12074cf49a43SJulian Elischer nl->numnames++; 12084cf49a43SJulian Elischer } 12094cf49a43SJulian Elischer *resp = rp; 12104cf49a43SJulian Elischer break; 12114cf49a43SJulian Elischer } 12124cf49a43SJulian Elischer 12134cf49a43SJulian Elischer case NGM_LISTTYPES: 12144cf49a43SJulian Elischer { 12154cf49a43SJulian Elischer struct typelist *tl; 12164cf49a43SJulian Elischer struct ng_mesg *rp; 12174cf49a43SJulian Elischer struct ng_type *type; 12184cf49a43SJulian Elischer int num = 0; 12194cf49a43SJulian Elischer 12204cf49a43SJulian Elischer if (resp == NULL) { 12214cf49a43SJulian Elischer error = EINVAL; 12224cf49a43SJulian Elischer break; 12234cf49a43SJulian Elischer } 12244cf49a43SJulian Elischer 12254cf49a43SJulian Elischer /* Count number of types */ 12264cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) 12274cf49a43SJulian Elischer num++; 12284cf49a43SJulian Elischer 12294cf49a43SJulian Elischer /* Get response struct */ 12304cf49a43SJulian Elischer if (resp == NULL) { 12314cf49a43SJulian Elischer error = EINVAL; 12324cf49a43SJulian Elischer break; 12334cf49a43SJulian Elischer } 12344cf49a43SJulian Elischer NG_MKRESPONSE(rp, msg, sizeof(*tl) 12354cf49a43SJulian Elischer + (num * sizeof(struct typeinfo)), M_NOWAIT); 12364cf49a43SJulian Elischer if (rp == NULL) { 12374cf49a43SJulian Elischer error = ENOMEM; 12384cf49a43SJulian Elischer break; 12394cf49a43SJulian Elischer } 12404cf49a43SJulian Elischer tl = (struct typelist *) rp->data; 12414cf49a43SJulian Elischer 12424cf49a43SJulian Elischer /* Cycle through the linked list of types */ 12434cf49a43SJulian Elischer tl->numtypes = 0; 12444cf49a43SJulian Elischer LIST_FOREACH(type, &typelist, types) { 12454cf49a43SJulian Elischer struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 12464cf49a43SJulian Elischer 12474cf49a43SJulian Elischer if (tl->numtypes >= num) { 12484cf49a43SJulian Elischer log(LOG_ERR, "%s: number of %s changed\n", 12494cf49a43SJulian Elischer __FUNCTION__, "types"); 12504cf49a43SJulian Elischer break; 12514cf49a43SJulian Elischer } 12524cf49a43SJulian Elischer strncpy(tp->typename, type->name, NG_TYPELEN); 12534cf49a43SJulian Elischer tp->numnodes = type->refs; 12544cf49a43SJulian Elischer tl->numtypes++; 12554cf49a43SJulian Elischer } 12564cf49a43SJulian Elischer *resp = rp; 12574cf49a43SJulian Elischer break; 12584cf49a43SJulian Elischer } 12594cf49a43SJulian Elischer 12604cf49a43SJulian Elischer case NGM_TEXT_STATUS: 12614cf49a43SJulian Elischer /* 12624cf49a43SJulian Elischer * This one is tricky as it passes the command down to the 12634cf49a43SJulian Elischer * actual node, even though it is a generic type command. 12644cf49a43SJulian Elischer * This means we must assume that the msg is already freed 12654cf49a43SJulian Elischer * when control passes back to us. 12664cf49a43SJulian Elischer */ 12674cf49a43SJulian Elischer if (resp == NULL) { 12684cf49a43SJulian Elischer error = EINVAL; 12694cf49a43SJulian Elischer break; 12704cf49a43SJulian Elischer } 12714cf49a43SJulian Elischer if (here->type->rcvmsg != NULL) 12724cf49a43SJulian Elischer return((*here->type->rcvmsg)(here, msg, retaddr, resp)); 12734cf49a43SJulian Elischer /* Fall through if rcvmsg not supported */ 12744cf49a43SJulian Elischer default: 12754cf49a43SJulian Elischer TRAP_ERROR; 12764cf49a43SJulian Elischer error = EINVAL; 12774cf49a43SJulian Elischer } 12784cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 12794cf49a43SJulian Elischer return (error); 12804cf49a43SJulian Elischer } 12814cf49a43SJulian Elischer 12824cf49a43SJulian Elischer /* 12834cf49a43SJulian Elischer * Send a data packet to a node. If the recipient has no 12844cf49a43SJulian Elischer * 'receive data' method, then silently discard the packet. 12854cf49a43SJulian Elischer */ 12864cf49a43SJulian Elischer int 12874cf49a43SJulian Elischer ng_send_data(hook_p hook, struct mbuf *m, meta_p meta) 12884cf49a43SJulian Elischer { 12894cf49a43SJulian Elischer int (*rcvdata)(hook_p, struct mbuf *, meta_p); 12904cf49a43SJulian Elischer int error; 12914cf49a43SJulian Elischer 12924cf49a43SJulian Elischer #ifdef DIAGNOSTIC 12934cf49a43SJulian Elischer if ((m->m_flags & M_PKTHDR) == 0) 12944cf49a43SJulian Elischer panic(__FUNCTION__); 12954cf49a43SJulian Elischer #endif 12964cf49a43SJulian Elischer if (hook && (hook->flags & HK_INVALID) == 0) { 12974cf49a43SJulian Elischer rcvdata = hook->peer->node->type->rcvdata; 12984cf49a43SJulian Elischer if (rcvdata != NULL) 12994cf49a43SJulian Elischer error = (*rcvdata)(hook->peer, m, meta); 13004cf49a43SJulian Elischer else { 13014cf49a43SJulian Elischer error = 0; 13024cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 13034cf49a43SJulian Elischer } 13044cf49a43SJulian Elischer } else { 13054cf49a43SJulian Elischer TRAP_ERROR; 13064cf49a43SJulian Elischer error = ENOTCONN; 13074cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 13084cf49a43SJulian Elischer } 13094cf49a43SJulian Elischer return (error); 13104cf49a43SJulian Elischer } 13114cf49a43SJulian Elischer 13124cf49a43SJulian Elischer /* 13134cf49a43SJulian Elischer * Send a queued data packet to a node. If the recipient has no 13144cf49a43SJulian Elischer * 'receive queued data' method, then try the 'receive data' method above. 13154cf49a43SJulian Elischer */ 13164cf49a43SJulian Elischer int 13174cf49a43SJulian Elischer ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta) 13184cf49a43SJulian Elischer { 13194cf49a43SJulian Elischer int (*rcvdataq)(hook_p, struct mbuf *, meta_p); 13204cf49a43SJulian Elischer int error; 13214cf49a43SJulian Elischer 13224cf49a43SJulian Elischer #ifdef DIAGNOSTIC 13234cf49a43SJulian Elischer if ((m->m_flags & M_PKTHDR) == 0) 13244cf49a43SJulian Elischer panic(__FUNCTION__); 13254cf49a43SJulian Elischer #endif 13264cf49a43SJulian Elischer if (hook && (hook->flags & HK_INVALID) == 0) { 13274cf49a43SJulian Elischer rcvdataq = hook->peer->node->type->rcvdataq; 13284cf49a43SJulian Elischer if (rcvdataq != NULL) 13294cf49a43SJulian Elischer error = (*rcvdataq)(hook->peer, m, meta); 13304cf49a43SJulian Elischer else { 13314cf49a43SJulian Elischer error = ng_send_data(hook, m, meta); 13324cf49a43SJulian Elischer } 13334cf49a43SJulian Elischer } else { 13344cf49a43SJulian Elischer TRAP_ERROR; 13354cf49a43SJulian Elischer error = ENOTCONN; 13364cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 13374cf49a43SJulian Elischer } 13384cf49a43SJulian Elischer return (error); 13394cf49a43SJulian Elischer } 13404cf49a43SJulian Elischer 13414cf49a43SJulian Elischer /************************************************************************ 13424cf49a43SJulian Elischer Module routines 13434cf49a43SJulian Elischer ************************************************************************/ 13444cf49a43SJulian Elischer 13454cf49a43SJulian Elischer /* 13464cf49a43SJulian Elischer * Handle the loading/unloading of a netgraph node type module 13474cf49a43SJulian Elischer */ 13484cf49a43SJulian Elischer int 13494cf49a43SJulian Elischer ng_mod_event(module_t mod, int event, void *data) 13504cf49a43SJulian Elischer { 13514cf49a43SJulian Elischer struct ng_type *const type = data; 13524cf49a43SJulian Elischer int s, error = 0; 13534cf49a43SJulian Elischer 13544cf49a43SJulian Elischer switch (event) { 13554cf49a43SJulian Elischer case MOD_LOAD: 13564cf49a43SJulian Elischer 13574cf49a43SJulian Elischer /* Register new netgraph node type */ 13584cf49a43SJulian Elischer s = splnet(); 13594cf49a43SJulian Elischer if ((error = ng_newtype(type)) != 0) { 13604cf49a43SJulian Elischer splx(s); 13614cf49a43SJulian Elischer break; 13624cf49a43SJulian Elischer } 13634cf49a43SJulian Elischer 13644cf49a43SJulian Elischer /* Call type specific code */ 13654cf49a43SJulian Elischer if (type->mod_event != NULL) 13664cf49a43SJulian Elischer if ((error = (*type->mod_event)(mod, event, data)) != 0) 13674cf49a43SJulian Elischer LIST_REMOVE(type, types); 13684cf49a43SJulian Elischer splx(s); 13694cf49a43SJulian Elischer break; 13704cf49a43SJulian Elischer 13714cf49a43SJulian Elischer case MOD_UNLOAD: 13724cf49a43SJulian Elischer s = splnet(); 13734cf49a43SJulian Elischer if (type->refs != 0) /* make sure no nodes exist! */ 13744cf49a43SJulian Elischer error = EBUSY; 13754cf49a43SJulian Elischer else { 13764cf49a43SJulian Elischer if (type->mod_event != NULL) { /* check with type */ 13774cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 13784cf49a43SJulian Elischer if (error != 0) { /* type refuses.. */ 13794cf49a43SJulian Elischer splx(s); 13804cf49a43SJulian Elischer break; 13814cf49a43SJulian Elischer } 13824cf49a43SJulian Elischer } 13834cf49a43SJulian Elischer LIST_REMOVE(type, types); 13844cf49a43SJulian Elischer } 13854cf49a43SJulian Elischer splx(s); 13864cf49a43SJulian Elischer break; 13874cf49a43SJulian Elischer 13884cf49a43SJulian Elischer default: 13894cf49a43SJulian Elischer if (type->mod_event != NULL) 13904cf49a43SJulian Elischer error = (*type->mod_event)(mod, event, data); 13914cf49a43SJulian Elischer else 13924cf49a43SJulian Elischer error = 0; /* XXX ? */ 13934cf49a43SJulian Elischer break; 13944cf49a43SJulian Elischer } 13954cf49a43SJulian Elischer return (error); 13964cf49a43SJulian Elischer } 13974cf49a43SJulian Elischer 13984cf49a43SJulian Elischer /* 13994cf49a43SJulian Elischer * Handle loading and unloading for this code. 14004cf49a43SJulian Elischer * The only thing we need to link into is the NETISR strucure. 14014cf49a43SJulian Elischer */ 14024cf49a43SJulian Elischer static int 14034cf49a43SJulian Elischer ngb_mod_event(module_t mod, int event, void *data) 14044cf49a43SJulian Elischer { 14054cf49a43SJulian Elischer int s, error = 0; 14064cf49a43SJulian Elischer 14074cf49a43SJulian Elischer switch (event) { 14084cf49a43SJulian Elischer case MOD_LOAD: 14094cf49a43SJulian Elischer /* Register line discipline */ 14104cf49a43SJulian Elischer s = splimp(); 14114cf49a43SJulian Elischer error = register_netisr(NETISR_NETGRAPH, ngintr); 14124cf49a43SJulian Elischer splx(s); 14134cf49a43SJulian Elischer break; 14144cf49a43SJulian Elischer case MOD_UNLOAD: 14154cf49a43SJulian Elischer /* You cant unload it because an interface may be using it. */ 14164cf49a43SJulian Elischer error = EBUSY; 14174cf49a43SJulian Elischer break; 14184cf49a43SJulian Elischer default: 14194cf49a43SJulian Elischer error = EOPNOTSUPP; 14204cf49a43SJulian Elischer break; 14214cf49a43SJulian Elischer } 14224cf49a43SJulian Elischer return (error); 14234cf49a43SJulian Elischer } 14244cf49a43SJulian Elischer 14254cf49a43SJulian Elischer static moduledata_t netgraph_mod = { 14264cf49a43SJulian Elischer "netgraph", 14274cf49a43SJulian Elischer ngb_mod_event, 14284cf49a43SJulian Elischer (NULL) 14294cf49a43SJulian Elischer }; 14304cf49a43SJulian Elischer DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 14314cf49a43SJulian Elischer 14324cf49a43SJulian Elischer /************************************************************************ 14334cf49a43SJulian Elischer Queueing routines 14344cf49a43SJulian Elischer ************************************************************************/ 14354cf49a43SJulian Elischer 14364cf49a43SJulian Elischer /* The structure for queueing across ISR switches */ 14374cf49a43SJulian Elischer struct ng_queue_entry { 14384cf49a43SJulian Elischer u_long flags; 14394cf49a43SJulian Elischer struct ng_queue_entry *next; 14404cf49a43SJulian Elischer union { 14414cf49a43SJulian Elischer struct { 14424cf49a43SJulian Elischer hook_p da_hook; /* target hook */ 14434cf49a43SJulian Elischer struct mbuf *da_m; 14444cf49a43SJulian Elischer meta_p da_meta; 14454cf49a43SJulian Elischer } data; 14464cf49a43SJulian Elischer struct { 14474cf49a43SJulian Elischer struct ng_mesg *msg_msg; 14484cf49a43SJulian Elischer node_p msg_node; 14494cf49a43SJulian Elischer void *msg_retaddr; 14504cf49a43SJulian Elischer } msg; 14514cf49a43SJulian Elischer } body; 14524cf49a43SJulian Elischer }; 14534cf49a43SJulian Elischer #define NGQF_DATA 0x01 /* the queue element is data */ 14544cf49a43SJulian Elischer #define NGQF_MESG 0x02 /* the queue element is a message */ 14554cf49a43SJulian Elischer 14564cf49a43SJulian Elischer static struct ng_queue_entry *ngqbase; /* items to be unqueued */ 14574cf49a43SJulian Elischer static struct ng_queue_entry *ngqlast; /* last item queued */ 14584cf49a43SJulian Elischer static const int ngqroom = 64; /* max items to queue */ 14594cf49a43SJulian Elischer static int ngqsize; /* number of items in queue */ 14604cf49a43SJulian Elischer 14614cf49a43SJulian Elischer static struct ng_queue_entry *ngqfree; /* free ones */ 14624cf49a43SJulian Elischer static const int ngqfreemax = 16;/* cache at most this many */ 14634cf49a43SJulian Elischer static int ngqfreesize; /* number of cached entries */ 14644cf49a43SJulian Elischer 14654cf49a43SJulian Elischer /* 14664cf49a43SJulian Elischer * Get a queue entry 14674cf49a43SJulian Elischer */ 14684cf49a43SJulian Elischer static struct ng_queue_entry * 14694cf49a43SJulian Elischer ng_getqblk(void) 14704cf49a43SJulian Elischer { 14714cf49a43SJulian Elischer register struct ng_queue_entry *q; 14724cf49a43SJulian Elischer int s; 14734cf49a43SJulian Elischer 14744cf49a43SJulian Elischer /* Could be guarding against tty ints or whatever */ 14754cf49a43SJulian Elischer s = splhigh(); 14764cf49a43SJulian Elischer 14774cf49a43SJulian Elischer /* Try get a cached queue block, or else allocate a new one */ 14784cf49a43SJulian Elischer if ((q = ngqfree) == NULL) { 14794cf49a43SJulian Elischer splx(s); 14804cf49a43SJulian Elischer if (ngqsize < ngqroom) { /* don't worry about races */ 14814cf49a43SJulian Elischer MALLOC(q, struct ng_queue_entry *, 14824cf49a43SJulian Elischer sizeof(*q), M_NETGRAPH, M_NOWAIT); 14834cf49a43SJulian Elischer } 14844cf49a43SJulian Elischer } else { 14854cf49a43SJulian Elischer ngqfree = q->next; 14864cf49a43SJulian Elischer ngqfreesize--; 14874cf49a43SJulian Elischer splx(s); 14884cf49a43SJulian Elischer } 14894cf49a43SJulian Elischer return (q); 14904cf49a43SJulian Elischer } 14914cf49a43SJulian Elischer 14924cf49a43SJulian Elischer /* 14934cf49a43SJulian Elischer * Release a queue entry 14944cf49a43SJulian Elischer */ 14954cf49a43SJulian Elischer #define RETURN_QBLK(q) \ 14964cf49a43SJulian Elischer do { \ 14974cf49a43SJulian Elischer int s; \ 14984cf49a43SJulian Elischer if (ngqfreesize < ngqfreemax) { /* don't worry about races */ \ 14994cf49a43SJulian Elischer s = splhigh(); \ 15004cf49a43SJulian Elischer (q)->next = ngqfree; \ 15014cf49a43SJulian Elischer ngqfree = (q); \ 15024cf49a43SJulian Elischer ngqfreesize++; \ 15034cf49a43SJulian Elischer splx(s); \ 15044cf49a43SJulian Elischer } else { \ 15054cf49a43SJulian Elischer FREE((q), M_NETGRAPH); \ 15064cf49a43SJulian Elischer } \ 15074cf49a43SJulian Elischer } while (0) 15084cf49a43SJulian Elischer 15094cf49a43SJulian Elischer /* 15104cf49a43SJulian Elischer * Running at a raised (but we don't know which) processor priority level, 15114cf49a43SJulian Elischer * put the data onto a queue to be picked up by another PPL (probably splnet) 15124cf49a43SJulian Elischer */ 15134cf49a43SJulian Elischer int 15144cf49a43SJulian Elischer ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta) 15154cf49a43SJulian Elischer { 15164cf49a43SJulian Elischer struct ng_queue_entry *q; 15174cf49a43SJulian Elischer int s; 15184cf49a43SJulian Elischer 15194cf49a43SJulian Elischer if (hook == NULL) { 15204cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 15214cf49a43SJulian Elischer return (0); 15224cf49a43SJulian Elischer } 15234cf49a43SJulian Elischer if ((q = ng_getqblk()) == NULL) { 15244cf49a43SJulian Elischer NG_FREE_DATA(m, meta); 15254cf49a43SJulian Elischer return (ENOBUFS); 15264cf49a43SJulian Elischer } 15274cf49a43SJulian Elischer 15284cf49a43SJulian Elischer /* Fill out the contents */ 15294cf49a43SJulian Elischer q->flags = NGQF_DATA; 15304cf49a43SJulian Elischer q->next = NULL; 15314cf49a43SJulian Elischer q->body.data.da_hook = hook; 15324cf49a43SJulian Elischer q->body.data.da_m = m; 15334cf49a43SJulian Elischer q->body.data.da_meta = meta; 15344cf49a43SJulian Elischer hook->refs++; /* don't let it go away while on the queue */ 15354cf49a43SJulian Elischer 15364cf49a43SJulian Elischer /* Put it on the queue */ 15374cf49a43SJulian Elischer s = splhigh(); 15384cf49a43SJulian Elischer if (ngqbase) { 15394cf49a43SJulian Elischer ngqlast->next = q; 15404cf49a43SJulian Elischer } else { 15414cf49a43SJulian Elischer ngqbase = q; 15424cf49a43SJulian Elischer } 15434cf49a43SJulian Elischer ngqlast = q; 15444cf49a43SJulian Elischer ngqsize++; 15454cf49a43SJulian Elischer splx(s); 15464cf49a43SJulian Elischer 15474cf49a43SJulian Elischer /* Schedule software interrupt to handle it later */ 15484cf49a43SJulian Elischer schednetisr(NETISR_NETGRAPH); 15494cf49a43SJulian Elischer return (0); 15504cf49a43SJulian Elischer } 15514cf49a43SJulian Elischer 15524cf49a43SJulian Elischer /* 15534cf49a43SJulian Elischer * Running at a raised (but we don't know which) processor priority level, 15544cf49a43SJulian Elischer * put the msg onto a queue to be picked up by another PPL (probably splnet) 15554cf49a43SJulian Elischer */ 15564cf49a43SJulian Elischer int 15574cf49a43SJulian Elischer ng_queue_msg(node_p here, struct ng_mesg * msg, int len, const char *address) 15584cf49a43SJulian Elischer { 15594cf49a43SJulian Elischer register struct ng_queue_entry *q; 15604cf49a43SJulian Elischer int s; 15614cf49a43SJulian Elischer node_p dest = NULL; 15624cf49a43SJulian Elischer char *retaddr = NULL; 15634cf49a43SJulian Elischer int error; 15644cf49a43SJulian Elischer 1565dc90cad9SJulian Elischer /* Find the target node. */ 15664cf49a43SJulian Elischer error = ng_path2node(here, address, &dest, &retaddr); 15674cf49a43SJulian Elischer if (error) { 15684cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 15694cf49a43SJulian Elischer return (error); 15704cf49a43SJulian Elischer } 15714cf49a43SJulian Elischer if ((q = ng_getqblk()) == NULL) { 15724cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 15734cf49a43SJulian Elischer if (retaddr) 15744cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 15754cf49a43SJulian Elischer return (ENOBUFS); 15764cf49a43SJulian Elischer } 15774cf49a43SJulian Elischer 15784cf49a43SJulian Elischer /* Fill out the contents */ 15794cf49a43SJulian Elischer q->flags = NGQF_MESG; 15804cf49a43SJulian Elischer q->next = NULL; 15814cf49a43SJulian Elischer q->body.msg.msg_node = dest; 15824cf49a43SJulian Elischer q->body.msg.msg_msg = msg; 15834cf49a43SJulian Elischer q->body.msg.msg_retaddr = retaddr; 15844cf49a43SJulian Elischer dest->refs++; /* don't let it go away while on the queue */ 15854cf49a43SJulian Elischer 15864cf49a43SJulian Elischer /* Put it on the queue */ 15874cf49a43SJulian Elischer s = splhigh(); 15884cf49a43SJulian Elischer if (ngqbase) { 15894cf49a43SJulian Elischer ngqlast->next = q; 15904cf49a43SJulian Elischer } else { 15914cf49a43SJulian Elischer ngqbase = q; 15924cf49a43SJulian Elischer } 15934cf49a43SJulian Elischer ngqlast = q; 15944cf49a43SJulian Elischer ngqsize++; 15954cf49a43SJulian Elischer splx(s); 15964cf49a43SJulian Elischer 15974cf49a43SJulian Elischer /* Schedule software interrupt to handle it later */ 15984cf49a43SJulian Elischer schednetisr(NETISR_NETGRAPH); 15994cf49a43SJulian Elischer return (0); 16004cf49a43SJulian Elischer } 16014cf49a43SJulian Elischer 16024cf49a43SJulian Elischer /* 16034cf49a43SJulian Elischer * Pick an item off the queue, process it, and dispose of the queue entry. 16044cf49a43SJulian Elischer * Should be running at splnet. 16054cf49a43SJulian Elischer */ 16064cf49a43SJulian Elischer static void 16074cf49a43SJulian Elischer ngintr(void) 16084cf49a43SJulian Elischer { 16094cf49a43SJulian Elischer hook_p hook; 16104cf49a43SJulian Elischer struct ng_queue_entry *ngq; 16114cf49a43SJulian Elischer struct mbuf *m; 16124cf49a43SJulian Elischer meta_p meta; 16134cf49a43SJulian Elischer void *retaddr; 16144cf49a43SJulian Elischer struct ng_mesg *msg; 16154cf49a43SJulian Elischer node_p node; 16164cf49a43SJulian Elischer int error = 0; 16174cf49a43SJulian Elischer int s; 16184cf49a43SJulian Elischer 16194cf49a43SJulian Elischer while (1) { 16204cf49a43SJulian Elischer s = splhigh(); 16214cf49a43SJulian Elischer if ((ngq = ngqbase)) { 16224cf49a43SJulian Elischer ngqbase = ngq->next; 16234cf49a43SJulian Elischer ngqsize--; 16244cf49a43SJulian Elischer } 16254cf49a43SJulian Elischer splx(s); 16264cf49a43SJulian Elischer if (ngq == NULL) 16274cf49a43SJulian Elischer return; 16284cf49a43SJulian Elischer switch (ngq->flags) { 16294cf49a43SJulian Elischer case NGQF_DATA: 16304cf49a43SJulian Elischer hook = ngq->body.data.da_hook; 16314cf49a43SJulian Elischer m = ngq->body.data.da_m; 16324cf49a43SJulian Elischer meta = ngq->body.data.da_meta; 16334cf49a43SJulian Elischer RETURN_QBLK(ngq); 16344cf49a43SJulian Elischer NG_SEND_DATAQ(error, hook, m, meta); 16354cf49a43SJulian Elischer ng_unref_hook(hook); 16364cf49a43SJulian Elischer break; 16374cf49a43SJulian Elischer case NGQF_MESG: 16384cf49a43SJulian Elischer node = ngq->body.msg.msg_node; 16394cf49a43SJulian Elischer msg = ngq->body.msg.msg_msg; 16404cf49a43SJulian Elischer retaddr = ngq->body.msg.msg_retaddr; 16414cf49a43SJulian Elischer RETURN_QBLK(ngq); 16424cf49a43SJulian Elischer if (node->flags & NG_INVALID) { 16434cf49a43SJulian Elischer FREE(msg, M_NETGRAPH); 16444cf49a43SJulian Elischer } else { 16454cf49a43SJulian Elischer CALL_MSG_HANDLER(error, node, msg, 16464cf49a43SJulian Elischer retaddr, NULL); 16474cf49a43SJulian Elischer } 16484cf49a43SJulian Elischer ng_unref(node); 16494cf49a43SJulian Elischer if (retaddr) 16504cf49a43SJulian Elischer FREE(retaddr, M_NETGRAPH); 16514cf49a43SJulian Elischer break; 16524cf49a43SJulian Elischer default: 16534cf49a43SJulian Elischer RETURN_QBLK(ngq); 16544cf49a43SJulian Elischer } 16554cf49a43SJulian Elischer } 16564cf49a43SJulian Elischer } 16574cf49a43SJulian Elischer 16584cf49a43SJulian Elischer 1659