ng_sample.c revision 141409
1227825Stheraven/* 2227825Stheraven * ng_sample.c 3227825Stheraven */ 4227825Stheraven 5227825Stheraven/*- 6227825Stheraven * Copyright (c) 1996-1999 Whistle Communications, Inc. 7227825Stheraven * All rights reserved. 8227825Stheraven * 9227825Stheraven * Subject to the following obligations and disclaimer of warranty, use and 10227825Stheraven * redistribution of this software, in source or object code forms, with or 11227825Stheraven * without modifications are expressly permitted by Whistle Communications; 12227825Stheraven * provided, however, that: 13227825Stheraven * 1. Any and all reproductions of the source or object code must include the 14227825Stheraven * copyright notice above and the following disclaimer of warranties; and 15227825Stheraven * 2. No rights are granted, in any manner or form, to use Whistle 16227825Stheraven * Communications, Inc. trademarks, including the mark "WHISTLE 17227825Stheraven * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18227825Stheraven * such appears in the above copyright notice or in the software. 19227825Stheraven * 20227825Stheraven * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21227825Stheraven * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22227825Stheraven * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23227825Stheraven * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24227825Stheraven * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25227825Stheraven * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26227825Stheraven * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27227825Stheraven * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28227825Stheraven * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29227825Stheraven * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30227825Stheraven * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31227825Stheraven * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32227825Stheraven * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33227825Stheraven * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34227825Stheraven * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35227825Stheraven * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36227825Stheraven * OF SUCH DAMAGE. 37227825Stheraven * 38227825Stheraven * Author: Julian Elischer <julian@freebsd.org> 39227825Stheraven * 40227825Stheraven * $FreeBSD: head/sys/netgraph/ng_sample.c 141409 2005-02-06 19:20:16Z glebius $ 41227825Stheraven * $Whistle: ng_sample.c,v 1.13 1999/11/01 09:24:52 julian Exp $ 42227825Stheraven */ 43227825Stheraven 44227825Stheraven#include <sys/param.h> 45227825Stheraven#include <sys/systm.h> 46227825Stheraven#include <sys/kernel.h> 47227825Stheraven#include <sys/mbuf.h> 48227825Stheraven#include <sys/malloc.h> 49227825Stheraven#include <sys/ctype.h> 50227825Stheraven#include <sys/errno.h> 51227825Stheraven#include <sys/syslog.h> 52227825Stheraven 53227825Stheraven#include <netgraph/ng_message.h> 54227825Stheraven#include <netgraph/ng_parse.h> 55227825Stheraven#include <netgraph/ng_sample.h> 56227825Stheraven#include <netgraph/netgraph.h> 57227825Stheraven 58227825Stheraven/* If you do complicated mallocs you may want to do this */ 59227825Stheraven/* and use it for your mallocs */ 60227825Stheraven#ifdef NG_SEPARATE_MALLOC 61227825StheravenMALLOC_DEFINE(M_NETGRAPH_XXX, "netgraph_xxx", "netgraph xxx node "); 62227825Stheraven#else 63227825Stheraven#define M_NETGRAPH_XXX M_NETGRAPH 64227825Stheraven#endif 65227825Stheraven 66227825Stheraven/* 67227825Stheraven * This section contains the netgraph method declarations for the 68227825Stheraven * sample node. These methods define the netgraph 'type'. 69227825Stheraven */ 70227825Stheraven 71227825Stheravenstatic ng_constructor_t ng_xxx_constructor; 72227825Stheravenstatic ng_rcvmsg_t ng_xxx_rcvmsg; 73227825Stheravenstatic ng_shutdown_t ng_xxx_shutdown; 74227825Stheravenstatic ng_newhook_t ng_xxx_newhook; 75227825Stheravenstatic ng_connect_t ng_xxx_connect; 76227825Stheravenstatic ng_rcvdata_t ng_xxx_rcvdata; 77227825Stheravenstatic ng_disconnect_t ng_xxx_disconnect; 78227825Stheraven 79227825Stheraven/* Parse type for struct ngxxxstat */ 80227825Stheravenstatic const struct ng_parse_struct_field ng_xxx_stat_type_fields[] 81227825Stheraven = NG_XXX_STATS_TYPE_INFO; 82227825Stheravenstatic const struct ng_parse_type ng_xxx_stat_type = { 83227825Stheraven &ng_parse_struct_type, 84227825Stheraven &ng_xxx_stat_type_fields 85227825Stheraven}; 86227825Stheraven 87227825Stheraven/* List of commands and how to convert arguments to/from ASCII */ 88227825Stheravenstatic const struct ng_cmdlist ng_xxx_cmdlist[] = { 89227825Stheraven { 90227825Stheraven NGM_XXX_COOKIE, 91227825Stheraven NGM_XXX_GET_STATUS, 92227825Stheraven "getstatus", 93227825Stheraven NULL, 94227825Stheraven &ng_xxx_stat_type, 95227825Stheraven }, 96227825Stheraven { 97227825Stheraven NGM_XXX_COOKIE, 98227825Stheraven NGM_XXX_SET_FLAG, 99227825Stheraven "setflag", 100227825Stheraven &ng_parse_int32_type, 101227825Stheraven NULL 102227825Stheraven }, 103227825Stheraven { 0 } 104227825Stheraven}; 105227825Stheraven 106227825Stheraven/* Netgraph node type descriptor */ 107227825Stheravenstatic struct ng_type typestruct = { 108227825Stheraven .version = NG_ABI_VERSION, 109227825Stheraven .name = NG_XXX_NODE_TYPE, 110227825Stheraven .constructor = ng_xxx_constructor, 111227825Stheraven .rcvmsg = ng_xxx_rcvmsg, 112227825Stheraven .shutdown = ng_xxx_shutdown, 113227825Stheraven .newhook = ng_xxx_newhook, 114227825Stheraven/* .findhook = ng_xxx_findhook, */ 115227825Stheraven .connect = ng_xxx_connect, 116227825Stheraven .rcvdata = ng_xxx_rcvdata, 117227825Stheraven .disconnect = ng_xxx_disconnect, 118227825Stheraven .cmdlist = ng_xxx_cmdlist, 119227825Stheraven}; 120227825StheravenNETGRAPH_INIT(xxx, &typestruct); 121227825Stheraven 122227825Stheraven/* Information we store for each hook on each node */ 123227825Stheravenstruct XXX_hookinfo { 124227825Stheraven int dlci; /* The DLCI it represents, -1 == downstream */ 125227825Stheraven int channel; /* The channel representing this DLCI */ 126227825Stheraven hook_p hook; 127227825Stheraven}; 128227825Stheraven 129227825Stheraven/* Information we store for each node */ 130227825Stheravenstruct XXX { 131227825Stheraven struct XXX_hookinfo channel[XXX_NUM_DLCIS]; 132227825Stheraven struct XXX_hookinfo downstream_hook; 133227825Stheraven node_p node; /* back pointer to node */ 134227825Stheraven hook_p debughook; 135227825Stheraven u_int packets_in; /* packets in from downstream */ 136227825Stheraven u_int packets_out; /* packets out towards downstream */ 137227825Stheraven u_int32_t flags; 138227825Stheraven}; 139227825Stheraventypedef struct XXX *xxx_p; 140227825Stheraven 141227825Stheraven/* 142227825Stheraven * Allocate the private data structure. The generic node has already 143227825Stheraven * been created. Link them together. We arrive with a reference to the node 144227825Stheraven * i.e. the reference count is incremented for us already. 145227825Stheraven * 146227825Stheraven * If this were a device node than this work would be done in the attach() 147227825Stheraven * routine and the constructor would return EINVAL as you should not be able 148227825Stheraven * to creatednodes that depend on hardware (unless you can add the hardware :) 149227825Stheraven */ 150227825Stheravenstatic int 151227825Stheravenng_xxx_constructor(node_p node) 152227825Stheraven{ 153227825Stheraven xxx_p privdata; 154227825Stheraven int i; 155227825Stheraven 156227825Stheraven /* Initialize private descriptor */ 157227825Stheraven MALLOC(privdata, xxx_p, sizeof(*privdata), M_NETGRAPH, 158227825Stheraven M_NOWAIT | M_ZERO); 159227825Stheraven if (privdata == NULL) 160227825Stheraven return (ENOMEM); 161227825Stheraven for (i = 0; i < XXX_NUM_DLCIS; i++) { 162227825Stheraven privdata->channel[i].dlci = -2; 163227825Stheraven privdata->channel[i].channel = i; 164227825Stheraven } 165227825Stheraven 166227825Stheraven /* Link structs together; this counts as our one reference to *nodep */ 167227825Stheraven NG_NODE_SET_PRIVATE(node, privdata); 168227825Stheraven privdata->node = node; 169227825Stheraven return (0); 170227825Stheraven} 171227825Stheraven 172227825Stheraven/* 173227825Stheraven * Give our ok for a hook to be added... 174227825Stheraven * If we are not running this might kick a device into life. 175227825Stheraven * Possibly decode information out of the hook name. 176227825Stheraven * Add the hook's private info to the hook structure. 177227825Stheraven * (if we had some). In this example, we assume that there is a 178227825Stheraven * an array of structs, called 'channel' in the private info, 179227825Stheraven * one for each active channel. The private 180227825Stheraven * pointer of each hook points to the appropriate XXX_hookinfo struct 181227825Stheraven * so that the source of an input packet is easily identified. 182227825Stheraven * (a dlci is a frame relay channel) 183227825Stheraven */ 184227825Stheravenstatic int 185227825Stheravenng_xxx_newhook(node_p node, hook_p hook, const char *name) 186227825Stheraven{ 187227825Stheraven const xxx_p xxxp = NG_NODE_PRIVATE(node); 188227825Stheraven const char *cp; 189227825Stheraven int dlci = 0; 190227825Stheraven int chan; 191227825Stheraven 192227825Stheraven#if 0 193227825Stheraven /* Possibly start up the device if it's not already going */ 194227825Stheraven if ((xxxp->flags & SCF_RUNNING) == 0) { 195227825Stheraven ng_xxx_start_hardware(xxxp); 196227825Stheraven } 197227825Stheraven#endif 198227825Stheraven 199227825Stheraven /* Example of how one might use hooks with embedded numbers: All 200227825Stheraven * hooks start with 'dlci' and have a decimal trailing channel 201227825Stheraven * number up to 4 digits Use the leadin defined int he associated .h 202227825Stheraven * file. */ 203227825Stheraven if (strncmp(name, 204227825Stheraven NG_XXX_HOOK_DLCI_LEADIN, strlen(NG_XXX_HOOK_DLCI_LEADIN)) == 0) { 205227825Stheraven char *eptr; 206227825Stheraven 207227825Stheraven cp = name + strlen(NG_XXX_HOOK_DLCI_LEADIN); 208227825Stheraven if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) 209227825Stheraven return (EINVAL); 210227825Stheraven dlci = (int)strtoul(cp, &eptr, 10); 211227825Stheraven if (*eptr != '\0' || dlci < 0 || dlci > 1023) 212227825Stheraven return (EINVAL); 213227825Stheraven 214227825Stheraven /* We have a dlci, now either find it, or allocate it */ 215227825Stheraven for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 216227825Stheraven if (xxxp->channel[chan].dlci == dlci) 217227825Stheraven break; 218227825Stheraven if (chan == XXX_NUM_DLCIS) { 219227825Stheraven for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 220227825Stheraven if (xxxp->channel[chan].dlci == -2) 221227825Stheraven break; 222227825Stheraven if (chan == XXX_NUM_DLCIS) 223227825Stheraven return (ENOBUFS); 224227825Stheraven xxxp->channel[chan].dlci = dlci; 225227825Stheraven } 226227825Stheraven if (xxxp->channel[chan].hook != NULL) 227227825Stheraven return (EADDRINUSE); 228227825Stheraven NG_HOOK_SET_PRIVATE(hook, xxxp->channel + chan); 229227825Stheraven xxxp->channel[chan].hook = hook; 230227825Stheraven return (0); 231227825Stheraven } else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) { 232227825Stheraven /* Example of simple predefined hooks. */ 233227825Stheraven /* do something specific to the downstream connection */ 234227825Stheraven xxxp->downstream_hook.hook = hook; 235227825Stheraven NG_HOOK_SET_PRIVATE(hook, &xxxp->downstream_hook); 236227825Stheraven } else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) { 237227825Stheraven /* do something specific to a debug connection */ 238227825Stheraven xxxp->debughook = hook; 239227825Stheraven NG_HOOK_SET_PRIVATE(hook, NULL); 240227825Stheraven } else 241227825Stheraven return (EINVAL); /* not a hook we know about */ 242227825Stheraven return(0); 243227825Stheraven} 244227825Stheraven 245227825Stheraven/* 246227825Stheraven * Get a netgraph control message. 247227825Stheraven * We actually recieve a queue item that has a pointer to the message. 248227825Stheraven * If we free the item, the message will be freed too, unless we remove 249227825Stheraven * it from the item using NGI_GET_MSG(); 250227825Stheraven * The return address is also stored in the item, as an ng_ID_t, 251227825Stheraven * accessible as NGI_RETADDR(item); 252227825Stheraven * Check it is one we understand. If needed, send a response. 253227825Stheraven * We could save the address for an async action later, but don't here. 254227825Stheraven * Always free the message. 255227825Stheraven * The response should be in a malloc'd region that the caller can 'free'. 256227825Stheraven * A response is not required. 257227825Stheraven * Theoretically you could respond defferently to old message types if 258227825Stheraven * the cookie in the header didn't match what we consider to be current 259227825Stheraven * (so that old userland programs could continue to work). 260227825Stheraven */ 261227825Stheravenstatic int 262227825Stheravenng_xxx_rcvmsg(node_p node, item_p item, hook_p lasthook) 263227825Stheraven{ 264227825Stheraven const xxx_p xxxp = NG_NODE_PRIVATE(node); 265227825Stheraven struct ng_mesg *resp = NULL; 266227825Stheraven int error = 0; 267227825Stheraven struct ng_mesg *msg; 268227825Stheraven 269227825Stheraven NGI_GET_MSG(item, msg); 270227825Stheraven /* Deal with message according to cookie and command */ 271227825Stheraven switch (msg->header.typecookie) { 272227825Stheraven case NGM_XXX_COOKIE: 273227825Stheraven switch (msg->header.cmd) { 274227825Stheraven case NGM_XXX_GET_STATUS: 275227825Stheraven { 276227825Stheraven struct ngxxxstat *stats; 277227825Stheraven 278227825Stheraven NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); 279227825Stheraven if (!resp) { 280227825Stheraven error = ENOMEM; 281227825Stheraven break; 282227825Stheraven } 283227825Stheraven stats = (struct ngxxxstat *) resp->data; 284227825Stheraven stats->packets_in = xxxp->packets_in; 285227825Stheraven stats->packets_out = xxxp->packets_out; 286227825Stheraven break; 287227825Stheraven } 288227825Stheraven case NGM_XXX_SET_FLAG: 289227825Stheraven if (msg->header.arglen != sizeof(u_int32_t)) { 290227825Stheraven error = EINVAL; 291227825Stheraven break; 292227825Stheraven } 293227825Stheraven xxxp->flags = *((u_int32_t *) msg->data); 294227825Stheraven break; 295227825Stheraven default: 296227825Stheraven error = EINVAL; /* unknown command */ 297227825Stheraven break; 298227825Stheraven } 299227825Stheraven break; 300227825Stheraven default: 301227825Stheraven error = EINVAL; /* unknown cookie type */ 302227825Stheraven break; 303227825Stheraven } 304227825Stheraven 305227825Stheraven /* Take care of synchronous response, if any */ 306227825Stheraven NG_RESPOND_MSG(error, node, item, resp); 307227825Stheraven /* Free the message and return */ 308227825Stheraven NG_FREE_MSG(msg); 309227825Stheraven return(error); 310227825Stheraven} 311227825Stheraven 312227825Stheraven/* 313227825Stheraven * Receive data, and do something with it. 314227825Stheraven * Actually we receive a queue item which holds the data. 315227825Stheraven * If we free the item it will also free the data unless we have 316227825Stheraven * previously disassociated it using the NGI_GET_M() macro. 317227825Stheraven * Possibly send it out on another link after processing. 318227825Stheraven * Possibly do something different if it comes from different 319227825Stheraven * hooks. The caller will never free m, so if we use up this data or 320227825Stheraven * abort we must free it. 321227825Stheraven * 322227825Stheraven * If we want, we may decide to force this data to be queued and reprocessed 323227825Stheraven * at the netgraph NETISR time. 324227825Stheraven * We would do that by setting the HK_QUEUE flag on our hook. We would do that 325227825Stheraven * in the connect() method. 326227825Stheraven */ 327227825Stheravenstatic int 328227825Stheravenng_xxx_rcvdata(hook_p hook, item_p item ) 329227825Stheraven{ 330227825Stheraven const xxx_p xxxp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 331227825Stheraven int chan = -2; 332227825Stheraven int dlci = -2; 333227825Stheraven int error; 334227825Stheraven struct mbuf *m; 335227825Stheraven 336227825Stheraven NGI_GET_M(item, m); 337227825Stheraven if (NG_HOOK_PRIVATE(hook)) { 338227825Stheraven dlci = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->dlci; 339227825Stheraven chan = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->channel; 340227825Stheraven if (dlci != -1) { 341227825Stheraven /* If received on a DLCI hook process for this 342227825Stheraven * channel and pass it to the downstream module. 343227825Stheraven * Normally one would add a multiplexing header at 344227825Stheraven * the front here */ 345227825Stheraven /* M_PREPEND(....) ; */ 346227825Stheraven /* mtod(m, xxxxxx)->dlci = dlci; */ 347227825Stheraven NG_FWD_NEW_DATA(error, item, 348227825Stheraven xxxp->downstream_hook.hook, m); 349227825Stheraven xxxp->packets_out++; 350227825Stheraven } else { 351227825Stheraven /* data came from the multiplexed link */ 352227825Stheraven dlci = 1; /* get dlci from header */ 353227825Stheraven /* madjust(....) *//* chop off header */ 354227825Stheraven for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 355227825Stheraven if (xxxp->channel[chan].dlci == dlci) 356227825Stheraven break; 357227825Stheraven if (chan == XXX_NUM_DLCIS) { 358227825Stheraven NG_FREE_ITEM(item); 359227825Stheraven NG_FREE_M(m); 360227825Stheraven return (ENETUNREACH); 361227825Stheraven } 362227825Stheraven /* If we were called at splnet, use the following: 363227825Stheraven * NG_SEND_DATA_ONLY(error, otherhook, m); if this 364227825Stheraven * node is running at some SPL other than SPLNET 365227825Stheraven * then you should use instead: error = 366227825Stheraven * ng_queueit(otherhook, m, NULL); m = NULL; 367227825Stheraven * This queues the data using the standard NETISR 368227825Stheraven * system and schedules the data to be picked 369227825Stheraven * up again once the system has moved to SPLNET and 370227825Stheraven * the processing of the data can continue. After 371227825Stheraven * these are run 'm' should be considered 372227825Stheraven * as invalid and NG_SEND_DATA actually zaps them. */ 373227825Stheraven NG_FWD_NEW_DATA(error, item, 374227825Stheraven xxxp->channel[chan].hook, m); 375227825Stheraven xxxp->packets_in++; 376227825Stheraven } 377227825Stheraven } else { 378227825Stheraven /* It's the debug hook, throw it away.. */ 379227825Stheraven if (hook == xxxp->downstream_hook.hook) { 380227825Stheraven NG_FREE_ITEM(item); 381227825Stheraven NG_FREE_M(m); 382227825Stheraven } 383227825Stheraven } 384227825Stheraven return 0; 385227825Stheraven} 386227825Stheraven 387227825Stheraven#if 0 388227825Stheraven/* 389227825Stheraven * If this were a device node, the data may have been received in response 390227825Stheraven * to some interrupt. 391227825Stheraven * in which case it would probably look as follows: 392227825Stheraven */ 393227825Stheravendevintr() 394227825Stheraven{ 395227825Stheraven int error; 396227825Stheraven 397227825Stheraven /* get packet from device and send on */ 398227825Stheraven m = MGET(blah blah) 399227825Stheraven 400227825Stheraven NG_SEND_DATA_ONLY(error, xxxp->upstream_hook.hook, m); 401227825Stheraven /* see note above in xxx_rcvdata() */ 402227825Stheraven /* and ng_xxx_connect() */ 403227825Stheraven} 404227825Stheraven 405227825Stheraven#endif /* 0 */ 406227825Stheraven 407227825Stheraven/* 408227825Stheraven * Do local shutdown processing.. 409227825Stheraven * All our links and the name have already been removed. 410227825Stheraven * If we are a persistant device, we might refuse to go away. 411227825Stheraven * In the case of a persistant node we signal the framework that we 412227825Stheraven * are still in business by clearing the NGF_INVALID bit. However 413227825Stheraven * If we find the NGF_REALLY_DIE bit set, this means that 414227825Stheraven * we REALLY need to die (e.g. hardware removed). 415227825Stheraven * This would have been set using the NG_NODE_REALLY_DIE(node) 416227825Stheraven * macro in some device dependent function (not shown here) before 417227825Stheraven * calling ng_rmnode_self(). 418227825Stheraven */ 419227825Stheravenstatic int 420227825Stheravenng_xxx_shutdown(node_p node) 421227825Stheraven{ 422227825Stheraven const xxx_p privdata = NG_NODE_PRIVATE(node); 423227825Stheraven 424227825Stheraven#ifndef PERSISTANT_NODE 425227825Stheraven NG_NODE_SET_PRIVATE(node, NULL); 426227825Stheraven NG_NODE_UNREF(node); 427227825Stheraven FREE(privdata, M_NETGRAPH); 428227825Stheraven#else 429227825Stheraven if (node->nd_flags & NGF_REALLY_DIE) { 430227825Stheraven /* 431227825Stheraven * WE came here because the widget card is being unloaded, 432227825Stheraven * so stop being persistant. 433227825Stheraven * Actually undo all the things we did on creation. 434227825Stheraven */ 435227825Stheraven NG_NODE_SET_PRIVATE(node, NULL); 436227825Stheraven NG_NODE_UNREF(privdata->node); 437227825Stheraven FREE(privdata, M_NETGRAPH); 438227825Stheraven return (0); 439227825Stheraven } 440227825Stheraven NG_NODE_REVIVE(node); /* tell ng_rmnode() we will persist */ 441227825Stheraven#endif /* PERSISTANT_NODE */ 442227825Stheraven return (0); 443227825Stheraven} 444227825Stheraven 445227825Stheraven/* 446227825Stheraven * This is called once we've already connected a new hook to the other node. 447227825Stheraven * It gives us a chance to balk at the last minute. 448227825Stheraven */ 449227825Stheravenstatic int 450227825Stheravenng_xxx_connect(hook_p hook) 451227825Stheraven{ 452227825Stheraven#if 0 453227825Stheraven /* 454227825Stheraven * If we were a driver running at other than splnet then 455227825Stheraven * we should set the QUEUE bit on the edge so that we 456227825Stheraven * will deliver by queing. 457227825Stheraven */ 458227825Stheraven if /*it is the upstream hook */ 459227825Stheraven NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 460227825Stheraven#endif 461227825Stheraven#if 0 462227825Stheraven /* 463227825Stheraven * If for some reason we want incoming date to be queued 464227825Stheraven * by the NETISR system and delivered later we can set the same bit on 465227825Stheraven * OUR hook. (maybe to allow unwinding of the stack) 466227825Stheraven */ 467227825Stheraven 468227825Stheraven if (NG_HOOK_PRIVATE(hook)) { 469227825Stheraven int dlci; 470227825Stheraven /* 471227825Stheraven * If it's dlci 1023, requeue it so that it's handled 472227825Stheraven * at a lower priority. This is how a node decides to 473227825Stheraven * defer a data message. 474227825Stheraven */ 475227825Stheraven dlci = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->dlci; 476227825Stheraven if (dlci == 1023) { 477227825Stheraven NG_HOOK_FORCE_QUEUE(hook); 478227825Stheraven } 479227825Stheraven#endif 480227825Stheraven /* otherwise be really amiable and just say "YUP that's OK by me! " */ 481227825Stheraven return (0); 482227825Stheraven} 483227825Stheraven 484227825Stheraven/* 485227825Stheraven * Hook disconnection 486227825Stheraven * 487227825Stheraven * For this type, removal of the last link destroys the node 488227825Stheraven */ 489227825Stheravenstatic int 490227825Stheravenng_xxx_disconnect(hook_p hook) 491227825Stheraven{ 492227825Stheraven if (NG_HOOK_PRIVATE(hook)) 493227825Stheraven ((struct XXX_hookinfo *) (NG_HOOK_PRIVATE(hook)))->hook = NULL; 494227825Stheraven if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 495227825Stheraven && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) /* already shutting down? */ 496227825Stheraven ng_rmnode_self(NG_HOOK_NODE(hook)); 497227825Stheraven return (0); 498227825Stheraven} 499227825Stheraven 500227825Stheraven