ng_sample.c revision 139688
1178825Sdfr
2233294Sstas/*
3233294Sstas * ng_sample.c
4233294Sstas *
5178825Sdfr * Copyright (c) 1996-1999 Whistle Communications, Inc.
6233294Sstas * All rights reserved.
7233294Sstas *
8233294Sstas * Subject to the following obligations and disclaimer of warranty, use and
9178825Sdfr * redistribution of this software, in source or object code forms, with or
10233294Sstas * without modifications are expressly permitted by Whistle Communications;
11233294Sstas * provided, however, that:
12178825Sdfr * 1. Any and all reproductions of the source or object code must include the
13233294Sstas *    copyright notice above and the following disclaimer of warranties; and
14233294Sstas * 2. No rights are granted, in any manner or form, to use Whistle
15233294Sstas *    Communications, Inc. trademarks, including the mark "WHISTLE
16178825Sdfr *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17233294Sstas *    such appears in the above copyright notice or in the software.
18233294Sstas *
19233294Sstas * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20178825Sdfr * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21233294Sstas * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22233294Sstas * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23233294Sstas * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24233294Sstas * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25233294Sstas * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26233294Sstas * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27233294Sstas * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28233294Sstas * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29233294Sstas * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30233294Sstas * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31233294Sstas * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32178825Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33178825Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34178825Sdfr * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35233294Sstas * OF SUCH DAMAGE.
36233294Sstas *
37178825Sdfr * Author: Julian Elischer <julian@freebsd.org>
38178825Sdfr *
39178825Sdfr * $FreeBSD: head/sys/netgraph/ng_sample.c 139688 2005-01-04 21:59:09Z rik $
40178825Sdfr * $Whistle: ng_sample.c,v 1.13 1999/11/01 09:24:52 julian Exp $
41178825Sdfr */
42178825Sdfr
43178825Sdfr#include <sys/param.h>
44178825Sdfr#include <sys/systm.h>
45178825Sdfr#include <sys/kernel.h>
46178825Sdfr#include <sys/mbuf.h>
47233294Sstas#include <sys/malloc.h>
48178825Sdfr#include <sys/ctype.h>
49178825Sdfr#include <sys/errno.h>
50178825Sdfr#include <sys/syslog.h>
51178825Sdfr
52178825Sdfr#include <netgraph/ng_message.h>
53178825Sdfr#include <netgraph/ng_parse.h>
54178825Sdfr#include <netgraph/ng_sample.h>
55178825Sdfr#include <netgraph/netgraph.h>
56178825Sdfr
57178825Sdfr/* If you do complicated mallocs you may want to do this */
58178825Sdfr/* and use it for your mallocs */
59178825Sdfr#ifdef NG_SEPARATE_MALLOC
60178825SdfrMALLOC_DEFINE(M_NETGRAPH_XXX, "netgraph_xxx", "netgraph xxx node ");
61178825Sdfr#else
62178825Sdfr#define M_NETGRAPH_XXX M_NETGRAPH
63178825Sdfr#endif
64178825Sdfr
65178825Sdfr/*
66233294Sstas * This section contains the netgraph method declarations for the
67233294Sstas * sample node. These methods define the netgraph 'type'.
68178825Sdfr */
69233294Sstas
70233294Sstasstatic ng_constructor_t	ng_xxx_constructor;
71233294Sstasstatic ng_rcvmsg_t	ng_xxx_rcvmsg;
72233294Sstasstatic ng_shutdown_t	ng_xxx_shutdown;
73233294Sstasstatic ng_newhook_t	ng_xxx_newhook;
74233294Sstasstatic ng_connect_t	ng_xxx_connect;
75233294Sstasstatic ng_rcvdata_t	ng_xxx_rcvdata;	 /* note these are both ng_rcvdata_t */
76233294Sstasstatic ng_disconnect_t	ng_xxx_disconnect;
77233294Sstas
78233294Sstas/* Parse type for struct ngxxxstat */
79233294Sstasstatic const struct ng_parse_struct_field ng_xxx_stat_type_fields[]
80178825Sdfr	= NG_XXX_STATS_TYPE_INFO;
81178825Sdfrstatic const struct ng_parse_type ng_xxx_stat_type = {
82178825Sdfr	&ng_parse_struct_type,
83233294Sstas	&ng_xxx_stat_type_fields
84178825Sdfr};
85178825Sdfr
86233294Sstas/* List of commands and how to convert arguments to/from ASCII */
87233294Sstasstatic const struct ng_cmdlist ng_xxx_cmdlist[] = {
88178825Sdfr	{
89178825Sdfr	  NGM_XXX_COOKIE,
90178825Sdfr	  NGM_XXX_GET_STATUS,
91178825Sdfr	  "getstatus",
92178825Sdfr	  NULL,
93178825Sdfr	  &ng_xxx_stat_type,
94178825Sdfr	},
95233294Sstas	{
96233294Sstas	  NGM_XXX_COOKIE,
97233294Sstas	  NGM_XXX_SET_FLAG,
98178825Sdfr	  "setflag",
99233294Sstas	  &ng_parse_int32_type,
100233294Sstas	  NULL
101178825Sdfr	},
102178825Sdfr	{ 0 }
103233294Sstas};
104233294Sstas
105178825Sdfr/* Netgraph node type descriptor */
106233294Sstasstatic struct ng_type typestruct = {
107233294Sstas	.version =	NG_ABI_VERSION,
108178825Sdfr	.name =		NG_XXX_NODE_TYPE,
109178825Sdfr	.constructor =	ng_xxx_constructor,
110233294Sstas	.rcvmsg =	ng_xxx_rcvmsg,
111233294Sstas	.shutdown =	ng_xxx_shutdown,
112178825Sdfr	.newhook =	ng_xxx_newhook,
113178825Sdfr/*	.findhook =	ng_xxx_findhook, 	*/
114178825Sdfr	.connect =	ng_xxx_connect,
115178825Sdfr	.rcvdata =	ng_xxx_rcvdata,
116178825Sdfr	.disconnect =	ng_xxx_disconnect,
117233294Sstas	.cmdlist =	ng_xxx_cmdlist,
118178825Sdfr};
119178825SdfrNETGRAPH_INIT(xxx, &typestruct);
120178825Sdfr
121178825Sdfr/* Information we store for each hook on each node */
122233294Sstasstruct XXX_hookinfo {
123178825Sdfr	int     dlci;		/* The DLCI it represents, -1 == downstream */
124178825Sdfr	int     channel;	/* The channel representing this DLCI */
125178825Sdfr	hook_p  hook;
126178825Sdfr};
127178825Sdfr
128233294Sstas/* Information we store for each node */
129178825Sdfrstruct XXX {
130178825Sdfr	struct XXX_hookinfo channel[XXX_NUM_DLCIS];
131178825Sdfr	struct XXX_hookinfo downstream_hook;
132178825Sdfr	node_p		node;		/* back pointer to node */
133178825Sdfr	hook_p  	debughook;
134178825Sdfr	u_int   	packets_in;	/* packets in from downstream */
135178825Sdfr	u_int   	packets_out;	/* packets out towards downstream */
136178825Sdfr	u_int32_t	flags;
137178825Sdfr};
138178825Sdfrtypedef struct XXX *xxx_p;
139178825Sdfr
140178825Sdfr/*
141178825Sdfr * Allocate the private data structure. The generic node has already
142178825Sdfr * been created. Link them together. We arrive with a reference to the node
143178825Sdfr * i.e. the reference count is incremented for us already.
144178825Sdfr *
145178825Sdfr * If this were a device node than this work would be done in the attach()
146178825Sdfr * routine and the constructor would return EINVAL as you should not be able
147178825Sdfr * to creatednodes that depend on hardware (unless you can add the hardware :)
148178825Sdfr */
149233294Sstasstatic int
150178825Sdfrng_xxx_constructor(node_p node)
151233294Sstas{
152178825Sdfr	xxx_p privdata;
153178825Sdfr	int i;
154178825Sdfr
155178825Sdfr	/* Initialize private descriptor */
156178825Sdfr	MALLOC(privdata, xxx_p, sizeof(*privdata), M_NETGRAPH,
157178825Sdfr		M_NOWAIT | M_ZERO);
158178825Sdfr	if (privdata == NULL)
159178825Sdfr		return (ENOMEM);
160178825Sdfr	for (i = 0; i < XXX_NUM_DLCIS; i++) {
161178825Sdfr		privdata->channel[i].dlci = -2;
162233294Sstas		privdata->channel[i].channel = i;
163233294Sstas	}
164178825Sdfr
165233294Sstas	/* Link structs together; this counts as our one reference to *nodep */
166178825Sdfr	NG_NODE_SET_PRIVATE(node, privdata);
167178825Sdfr	privdata->node = node;
168178825Sdfr	return (0);
169178825Sdfr}
170233294Sstas
171178825Sdfr/*
172178825Sdfr * Give our ok for a hook to be added...
173178825Sdfr * If we are not running this might kick a device into life.
174178825Sdfr * Possibly decode information out of the hook name.
175178825Sdfr * Add the hook's private info to the hook structure.
176178825Sdfr * (if we had some). In this example, we assume that there is a
177178825Sdfr * an array of structs, called 'channel' in the private info,
178178825Sdfr * one for each active channel. The private
179178825Sdfr * pointer of each hook points to the appropriate XXX_hookinfo struct
180178825Sdfr * so that the source of an input packet is easily identified.
181178825Sdfr * (a dlci is a frame relay channel)
182178825Sdfr */
183178825Sdfrstatic int
184178825Sdfrng_xxx_newhook(node_p node, hook_p hook, const char *name)
185178825Sdfr{
186178825Sdfr	const xxx_p xxxp = NG_NODE_PRIVATE(node);
187178825Sdfr	const char *cp;
188178825Sdfr	int dlci = 0;
189178825Sdfr	int chan;
190178825Sdfr
191178825Sdfr#if 0
192178825Sdfr	/* Possibly start up the device if it's not already going */
193178825Sdfr	if ((xxxp->flags & SCF_RUNNING) == 0) {
194178825Sdfr		ng_xxx_start_hardware(xxxp);
195178825Sdfr	}
196178825Sdfr#endif
197178825Sdfr
198178825Sdfr	/* Example of how one might use hooks with embedded numbers: All
199178825Sdfr	 * hooks start with 'dlci' and have a decimal trailing channel
200178825Sdfr	 * number up to 4 digits Use the leadin defined int he associated .h
201178825Sdfr	 * file. */
202178825Sdfr	if (strncmp(name,
203178825Sdfr	    NG_XXX_HOOK_DLCI_LEADIN, strlen(NG_XXX_HOOK_DLCI_LEADIN)) == 0) {
204233294Sstas		char *eptr;
205233294Sstas
206178825Sdfr		cp = name + strlen(NG_XXX_HOOK_DLCI_LEADIN);
207178825Sdfr		if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0'))
208178825Sdfr			return (EINVAL);
209178825Sdfr		dlci = (int)strtoul(cp, &eptr, 10);
210178825Sdfr		if (*eptr != '\0' || dlci < 0 || dlci > 1023)
211233294Sstas			return (EINVAL);
212233294Sstas
213233294Sstas		/* We have a dlci, now either find it, or allocate it */
214178825Sdfr		for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
215178825Sdfr			if (xxxp->channel[chan].dlci == dlci)
216178825Sdfr				break;
217178825Sdfr		if (chan == XXX_NUM_DLCIS) {
218178825Sdfr			for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
219233294Sstas				if (xxxp->channel[chan].dlci == -2)
220178825Sdfr					break;
221178825Sdfr			if (chan == XXX_NUM_DLCIS)
222178825Sdfr				return (ENOBUFS);
223178825Sdfr			xxxp->channel[chan].dlci = dlci;
224233294Sstas		}
225233294Sstas		if (xxxp->channel[chan].hook != NULL)
226178825Sdfr			return (EADDRINUSE);
227178825Sdfr		NG_HOOK_SET_PRIVATE(hook, xxxp->channel + chan);
228233294Sstas		xxxp->channel[chan].hook = hook;
229233294Sstas		return (0);
230178825Sdfr	} else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) {
231178825Sdfr		/* Example of simple predefined hooks. */
232178825Sdfr		/* do something specific to the downstream connection */
233233294Sstas		xxxp->downstream_hook.hook = hook;
234178825Sdfr		NG_HOOK_SET_PRIVATE(hook, &xxxp->downstream_hook);
235178825Sdfr	} else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) {
236233294Sstas		/* do something specific to a debug connection */
237178825Sdfr		xxxp->debughook = hook;
238178825Sdfr		NG_HOOK_SET_PRIVATE(hook, NULL);
239178825Sdfr	} else
240233294Sstas		return (EINVAL);	/* not a hook we know about */
241233294Sstas	return(0);
242233294Sstas}
243233294Sstas
244233294Sstas/*
245178825Sdfr * Get a netgraph control message.
246178825Sdfr * We actually recieve a queue item that has a pointer to the message.
247233294Sstas * If we free the item, the message will be freed too, unless we remove
248233294Sstas * it from the item using NGI_GET_MSG();
249233294Sstas * The return address is also stored in the item, as an ng_ID_t,
250233294Sstas * accessible as NGI_RETADDR(item);
251233294Sstas * Check it is one we understand. If needed, send a response.
252178825Sdfr * We could save the address for an async action later, but don't here.
253233294Sstas * Always free the message.
254178825Sdfr * The response should be in a malloc'd region that the caller can 'free'.
255178825Sdfr * A response is not required.
256178825Sdfr * Theoretically you could respond defferently to old message types if
257233294Sstas * the cookie in the header didn't match what we consider to be current
258233294Sstas * (so that old userland programs could continue to work).
259178825Sdfr */
260178825Sdfrstatic int
261233294Sstasng_xxx_rcvmsg(node_p node, item_p item, hook_p lasthook)
262178825Sdfr{
263178825Sdfr	const xxx_p xxxp = NG_NODE_PRIVATE(node);
264178825Sdfr	struct ng_mesg *resp = NULL;
265233294Sstas	int error = 0;
266233294Sstas	struct ng_mesg *msg;
267233294Sstas
268233294Sstas	NGI_GET_MSG(item, msg);
269233294Sstas	/* Deal with message according to cookie and command */
270178825Sdfr	switch (msg->header.typecookie) {
271178825Sdfr	case NGM_XXX_COOKIE:
272233294Sstas		switch (msg->header.cmd) {
273233294Sstas		case NGM_XXX_GET_STATUS:
274233294Sstas		    {
275233294Sstas			struct ngxxxstat *stats;
276233294Sstas
277178825Sdfr			NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
278233294Sstas			if (!resp) {
279178825Sdfr				error = ENOMEM;
280178825Sdfr				break;
281178825Sdfr			}
282178825Sdfr			stats = (struct ngxxxstat *) resp->data;
283178825Sdfr			stats->packets_in = xxxp->packets_in;
284178825Sdfr			stats->packets_out = xxxp->packets_out;
285178825Sdfr			break;
286178825Sdfr		    }
287178825Sdfr		case NGM_XXX_SET_FLAG:
288178825Sdfr			if (msg->header.arglen != sizeof(u_int32_t)) {
289233294Sstas				error = EINVAL;
290233294Sstas				break;
291178825Sdfr			}
292178825Sdfr			xxxp->flags = *((u_int32_t *) msg->data);
293178825Sdfr			break;
294178825Sdfr		default:
295178825Sdfr			error = EINVAL;		/* unknown command */
296178825Sdfr			break;
297178825Sdfr		}
298178825Sdfr		break;
299178825Sdfr	default:
300178825Sdfr		error = EINVAL;			/* unknown cookie type */
301178825Sdfr		break;
302178825Sdfr	}
303178825Sdfr
304233294Sstas	/* Take care of synchronous response, if any */
305233294Sstas	NG_RESPOND_MSG(error, node, item, resp);
306233294Sstas	/* Free the message and return */
307233294Sstas	NG_FREE_MSG(msg);
308233294Sstas	return(error);
309233294Sstas}
310233294Sstas
311178825Sdfr/*
312178825Sdfr * Receive data, and do something with it.
313233294Sstas * Actually we receive a queue item which holds the data.
314233294Sstas * If we free the item it will also free the data unless we have
315233294Sstas * previously disassociated it using the NGI_GET_M() macro.
316233294Sstas * Possibly send it out on another link after processing.
317233294Sstas * Possibly do something different if it comes from different
318233294Sstas * hooks. The caller will never free m, so if we use up this data or
319233294Sstas * abort we must free it.
320233294Sstas *
321233294Sstas * If we want, we may decide to force this data to be queued and reprocessed
322233294Sstas * at the netgraph NETISR time.
323233294Sstas * We would do that by setting the HK_QUEUE flag on our hook. We would do that
324233294Sstas * in the connect() method.
325233294Sstas */
326233294Sstasstatic int
327233294Sstasng_xxx_rcvdata(hook_p hook, item_p item )
328233294Sstas{
329233294Sstas	const xxx_p xxxp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
330233294Sstas	int chan = -2;
331233294Sstas	int dlci = -2;
332233294Sstas	int error;
333178825Sdfr	struct mbuf *m;
334233294Sstas
335233294Sstas	NGI_GET_M(item, m);
336233294Sstas	if (NG_HOOK_PRIVATE(hook)) {
337233294Sstas		dlci = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->dlci;
338178825Sdfr		chan = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->channel;
339233294Sstas		if (dlci != -1) {
340233294Sstas			/* If received on a DLCI hook process for this
341178825Sdfr			 * channel and pass it to the downstream module.
342233294Sstas			 * Normally one would add a multiplexing header at
343178825Sdfr			 * the front here */
344233294Sstas			/* M_PREPEND(....)	; */
345233294Sstas			/* mtod(m, xxxxxx)->dlci = dlci; */
346178825Sdfr			NG_FWD_NEW_DATA(error, item,
347233294Sstas				xxxp->downstream_hook.hook, m);
348233294Sstas			xxxp->packets_out++;
349233294Sstas		} else {
350233294Sstas			/* data came from the multiplexed link */
351233294Sstas			dlci = 1;	/* get dlci from header */
352178825Sdfr			/* madjust(....) *//* chop off header */
353233294Sstas			for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
354233294Sstas				if (xxxp->channel[chan].dlci == dlci)
355178825Sdfr					break;
356233294Sstas			if (chan == XXX_NUM_DLCIS) {
357233294Sstas				NG_FREE_ITEM(item);
358233294Sstas				NG_FREE_M(m);
359178825Sdfr				return (ENETUNREACH);
360178825Sdfr			}
361233294Sstas			/* If we were called at splnet, use the following:
362233294Sstas			 * NG_SEND_DATA_ONLY(error, otherhook, m); if this
363178825Sdfr			 * node is running at some SPL other than SPLNET
364233294Sstas			 * then you should use instead: error =
365233294Sstas			 * ng_queueit(otherhook, m, NULL); m = NULL;
366233294Sstas			 * This queues the data using the standard NETISR
367233294Sstas			 * system and schedules the data to be picked
368233294Sstas			 * up again once the system has moved to SPLNET and
369233294Sstas			 * the processing of the data can continue. After
370233294Sstas			 * these are run 'm' should be considered
371233294Sstas			 * as invalid and NG_SEND_DATA actually zaps them. */
372233294Sstas			NG_FWD_NEW_DATA(error, item,
373233294Sstas				xxxp->channel[chan].hook, m);
374233294Sstas			xxxp->packets_in++;
375233294Sstas		}
376233294Sstas	} else {
377178825Sdfr		/* It's the debug hook, throw it away.. */
378178825Sdfr		if (hook == xxxp->downstream_hook.hook) {
379233294Sstas			NG_FREE_ITEM(item);
380178825Sdfr			NG_FREE_M(m);
381233294Sstas		}
382233294Sstas	}
383233294Sstas	return 0;
384233294Sstas}
385233294Sstas
386233294Sstas#if 0
387233294Sstas/*
388233294Sstas * If this were a device node, the data may have been received in response
389233294Sstas * to some interrupt.
390233294Sstas * in which case it would probably look as follows:
391233294Sstas */
392233294Sstasdevintr()
393233294Sstas{
394233294Sstas	int error;
395233294Sstas
396233294Sstas	/* get packet from device and send on */
397233294Sstas	m = MGET(blah blah)
398233294Sstas
399233294Sstas	NG_SEND_DATA_ONLY(error, xxxp->upstream_hook.hook, m);
400233294Sstas				/* see note above in xxx_rcvdata() */
401233294Sstas				/* and ng_xxx_connect() */
402233294Sstas}
403233294Sstas
404233294Sstas#endif				/* 0 */
405233294Sstas
406178825Sdfr/*
407178825Sdfr * Do local shutdown processing..
408178825Sdfr * All our links and the name have already been removed.
409233294Sstas * If we are a persistant device, we might refuse to go away.
410233294Sstas * In the case of a persistant node we signal the framework that we
411233294Sstas * are still in business by clearing the NGF_INVALID bit. However
412178825Sdfr * If we find the NGF_REALLY_DIE bit set, this means that
413233294Sstas * we REALLY need to die (e.g. hardware removed).
414233294Sstas * This would have been set using the NG_NODE_REALLY_DIE(node)
415233294Sstas * macro in some device dependent function (not shown here) before
416178825Sdfr * calling ng_rmnode_self().
417233294Sstas */
418233294Sstasstatic int
419233294Sstasng_xxx_shutdown(node_p node)
420233294Sstas{
421233294Sstas	const xxx_p privdata = NG_NODE_PRIVATE(node);
422233294Sstas
423233294Sstas#ifndef PERSISTANT_NODE
424233294Sstas	NG_NODE_SET_PRIVATE(node, NULL);
425178825Sdfr	NG_NODE_UNREF(node);
426233294Sstas	FREE(privdata, M_NETGRAPH);
427233294Sstas#else
428233294Sstas	if (node->nd_flags & NGF_REALLY_DIE) {
429233294Sstas		/*
430233294Sstas		 * WE came here because the widget card is being unloaded,
431233294Sstas		 * so stop being persistant.
432233294Sstas		 * Actually undo all the things we did on creation.
433233294Sstas		 */
434233294Sstas		NG_NODE_SET_PRIVATE(node, NULL);
435233294Sstas		NG_NODE_UNREF(privdata->node);
436233294Sstas		FREE(privdata, M_NETGRAPH);
437233294Sstas		return (0);
438233294Sstas        }
439233294Sstas	NG_NODE_REVIVE(node);		/* tell ng_rmnode() we will persist */
440233294Sstas#endif /* PERSISTANT_NODE */
441233294Sstas	return (0);
442233294Sstas}
443233294Sstas
444233294Sstas/*
445233294Sstas * This is called once we've already connected a new hook to the other node.
446233294Sstas * It gives us a chance to balk at the last minute.
447233294Sstas */
448233294Sstasstatic int
449233294Sstasng_xxx_connect(hook_p hook)
450233294Sstas{
451178825Sdfr#if 0
452233294Sstas	/*
453233294Sstas	 * If we were a driver running at other than splnet then
454233294Sstas	 * we should set the QUEUE bit on the edge so that we
455178825Sdfr	 * will deliver by queing.
456178825Sdfr	 */
457233294Sstas	if /*it is the upstream hook */
458233294Sstas	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
459233294Sstas#endif
460233294Sstas#if 0
461233294Sstas	/*
462233294Sstas	 * If for some reason we want incoming date to be queued
463233294Sstas	 * by the NETISR system and delivered later we can set the same bit on
464233294Sstas	 * OUR hook. (maybe to allow unwinding of the stack)
465233294Sstas	 */
466233294Sstas
467233294Sstas	if (NG_HOOK_PRIVATE(hook)) {
468233294Sstas		int dlci;
469178825Sdfr		/*
470178825Sdfr		 * If it's dlci 1023, requeue it so that it's handled
471233294Sstas		 * at a lower priority. This is how a node decides to
472178825Sdfr		 * defer a data message.
473178825Sdfr		 */
474178825Sdfr		dlci = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->dlci;
475178825Sdfr		if (dlci == 1023) {
476178825Sdfr			NG_HOOK_FORCE_QUEUE(hook);
477178825Sdfr		}
478178825Sdfr#endif
479178825Sdfr	/* otherwise be really amiable and just say "YUP that's OK by me! " */
480178825Sdfr	return (0);
481178825Sdfr}
482178825Sdfr
483178825Sdfr/*
484178825Sdfr * Hook disconnection
485178825Sdfr *
486178825Sdfr * For this type, removal of the last link destroys the node
487178825Sdfr */
488178825Sdfrstatic int
489178825Sdfrng_xxx_disconnect(hook_p hook)
490233294Sstas{
491233294Sstas	if (NG_HOOK_PRIVATE(hook))
492233294Sstas		((struct XXX_hookinfo *) (NG_HOOK_PRIVATE(hook)))->hook = NULL;
493233294Sstas	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
494233294Sstas	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) /* already shutting down? */
495178825Sdfr		ng_rmnode_self(NG_HOOK_NODE(hook));
496178825Sdfr	return (0);
497178825Sdfr}
498178825Sdfr
499178825Sdfr