1139823Simp/*-
2121461Sharti * Copyright (c) 2001-2003
3121461Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4121461Sharti * 	All rights reserved.
5121461Sharti *
6121461Sharti * Redistribution and use in source and binary forms, with or without
7121461Sharti * modification, are permitted provided that the following conditions
8121461Sharti * are met:
9121461Sharti * 1. Redistributions of source code must retain the above copyright
10121461Sharti *    notice, this list of conditions and the following disclaimer.
11121461Sharti * 2. Redistributions in binary form must reproduce the above copyright
12121461Sharti *    notice, this list of conditions and the following disclaimer in the
13121461Sharti *    documentation and/or other materials provided with the distribution.
14121461Sharti *
15121461Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16121461Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17121461Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18121461Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19121461Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20121461Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21121461Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22121461Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23121461Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24121461Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25121461Sharti * SUCH DAMAGE.
26121461Sharti *
27121461Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28121461Sharti *
29121461Sharti * Netgraph module for ITU-T Q.2120 UNI SSCF.
30121461Sharti */
31121461Sharti
32121461Sharti#include <sys/cdefs.h>
33121461Sharti__FBSDID("$FreeBSD$");
34121461Sharti
35121461Sharti#include <sys/param.h>
36121461Sharti#include <sys/systm.h>
37121461Sharti#include <sys/kernel.h>
38121461Sharti#include <sys/malloc.h>
39121461Sharti#include <sys/mbuf.h>
40121461Sharti#include <sys/errno.h>
41121461Sharti#include <sys/syslog.h>
42121461Sharti#include <sys/socket.h>
43121461Sharti#include <sys/socketvar.h>
44121461Sharti#include <sys/sbuf.h>
45121461Sharti#include <machine/stdarg.h>
46121461Sharti
47121461Sharti#include <netgraph/ng_message.h>
48121461Sharti#include <netgraph/netgraph.h>
49121461Sharti#include <netgraph/ng_parse.h>
50121461Sharti#include <netnatm/saal/sscopdef.h>
51121461Sharti#include <netnatm/saal/sscfudef.h>
52121461Sharti#include <netgraph/atm/ng_sscop.h>
53121461Sharti#include <netgraph/atm/ng_sscfu.h>
54121461Sharti#include <netgraph/atm/sscfu/ng_sscfu_cust.h>
55121461Sharti#include <netnatm/saal/sscfu.h>
56121461Sharti
57121461ShartiMALLOC_DEFINE(M_NG_SSCFU, "netgraph_sscfu", "netgraph uni sscf node");
58121461Sharti
59121461ShartiMODULE_DEPEND(ng_sscfu, ngatmbase, 1, 1, 1);
60121461Sharti
61121461Sharti/*
62121461Sharti * Private data
63121461Sharti */
64121461Shartistruct priv {
65121461Sharti	hook_p		upper;	/* SAAL interface */
66121461Sharti	hook_p		lower;	/* SSCOP interface */
67121461Sharti	struct sscfu	*sscf;	/* the instance */
68121461Sharti	int		enabled;
69121461Sharti};
70121461Sharti
71121461Sharti/*
72121461Sharti * PARSING
73121461Sharti */
74121461Sharti/*
75121461Sharti * Parse PARAM type
76121461Sharti */
77121461Shartistatic const struct ng_parse_struct_field ng_sscop_param_type_info[] =
78121461Sharti    NG_SSCOP_PARAM_INFO;
79121461Sharti
80121461Shartistatic const struct ng_parse_type ng_sscop_param_type = {
81121461Sharti	&ng_parse_struct_type,
82121461Sharti	ng_sscop_param_type_info
83121461Sharti};
84121461Sharti
85121461Shartistatic const struct ng_parse_struct_field ng_sscfu_getdefparam_type_info[] =
86121461Sharti    NG_SSCFU_GETDEFPARAM_INFO;
87121461Sharti
88121461Shartistatic const struct ng_parse_type ng_sscfu_getdefparam_type = {
89121461Sharti	&ng_parse_struct_type,
90121461Sharti	ng_sscfu_getdefparam_type_info
91121461Sharti};
92121461Sharti
93121461Sharti
94121461Shartistatic const struct ng_cmdlist ng_sscfu_cmdlist[] = {
95121461Sharti	{
96121461Sharti	  NGM_SSCFU_COOKIE,
97121461Sharti	  NGM_SSCFU_GETDEFPARAM,
98121461Sharti	  "getdefparam",
99121461Sharti	  NULL,
100121461Sharti	  &ng_sscfu_getdefparam_type
101121461Sharti	},
102121461Sharti	{
103121461Sharti	  NGM_SSCFU_COOKIE,
104121461Sharti	  NGM_SSCFU_ENABLE,
105121461Sharti	  "enable",
106121461Sharti	  NULL,
107121461Sharti	  NULL
108121461Sharti	},
109121461Sharti	{
110121461Sharti	  NGM_SSCFU_COOKIE,
111121461Sharti	  NGM_SSCFU_DISABLE,
112121461Sharti	  "disable",
113121461Sharti	  NULL,
114121461Sharti	  NULL
115121461Sharti	},
116121461Sharti	{
117121461Sharti	  NGM_SSCFU_COOKIE,
118121461Sharti	  NGM_SSCFU_GETDEBUG,
119121461Sharti	  "getdebug",
120121461Sharti	  NULL,
121121461Sharti	  &ng_parse_hint32_type
122121461Sharti	},
123121461Sharti	{
124121461Sharti	  NGM_SSCFU_COOKIE,
125121461Sharti	  NGM_SSCFU_SETDEBUG,
126121461Sharti	  "setdebug",
127121461Sharti	  &ng_parse_hint32_type,
128121461Sharti	  NULL
129121461Sharti	},
130121461Sharti	{
131121461Sharti	  NGM_SSCFU_COOKIE,
132121461Sharti	  NGM_SSCFU_GETSTATE,
133121461Sharti	  "getstate",
134121461Sharti	  NULL,
135121461Sharti	  &ng_parse_uint32_type
136121461Sharti	},
137121461Sharti	{ 0 }
138121461Sharti};
139121461Sharti
140121461Shartistatic ng_constructor_t ng_sscfu_constructor;
141121461Shartistatic ng_shutdown_t	ng_sscfu_shutdown;
142121461Shartistatic ng_rcvmsg_t	ng_sscfu_rcvmsg;
143121461Shartistatic ng_newhook_t	ng_sscfu_newhook;
144121461Shartistatic ng_disconnect_t	ng_sscfu_disconnect;
145121461Shartistatic ng_rcvdata_t	ng_sscfu_rcvupper;
146121461Shartistatic ng_rcvdata_t	ng_sscfu_rcvlower;
147121461Sharti
148121461Shartistatic int ng_sscfu_mod_event(module_t, int, void *);
149121461Sharti
150121461Shartistatic struct ng_type ng_sscfu_typestruct = {
151129823Sjulian	.version =	NG_ABI_VERSION,
152129823Sjulian	.name =		NG_SSCFU_NODE_TYPE,
153129823Sjulian	.mod_event =	ng_sscfu_mod_event,
154129823Sjulian	.constructor =	ng_sscfu_constructor,
155129823Sjulian	.rcvmsg =	ng_sscfu_rcvmsg,
156129823Sjulian	.shutdown =	ng_sscfu_shutdown,
157129823Sjulian	.newhook =	ng_sscfu_newhook,
158129823Sjulian	.rcvdata =	ng_sscfu_rcvupper,
159129823Sjulian	.disconnect =	ng_sscfu_disconnect,
160129823Sjulian	.cmdlist =	ng_sscfu_cmdlist,
161121461Sharti};
162121461ShartiNETGRAPH_INIT(sscfu, &ng_sscfu_typestruct);
163121461Sharti
164121461Shartistatic void sscfu_send_upper(struct sscfu *, void *, enum saal_sig,
165121461Sharti	struct mbuf *);
166121461Shartistatic void sscfu_send_lower(struct sscfu *, void *, enum sscop_aasig,
167121461Sharti	struct mbuf *, u_int);
168121461Shartistatic void sscfu_window(struct sscfu *, void *, u_int);
169121461Shartistatic void sscfu_verbose(struct sscfu *, void *, const char *, ...)
170121461Sharti	__printflike(3, 4);
171121461Sharti
172121461Shartistatic const struct sscfu_funcs sscfu_funcs = {
173121461Sharti	sscfu_send_upper,
174121461Sharti	sscfu_send_lower,
175121461Sharti	sscfu_window,
176121461Sharti	sscfu_verbose
177121461Sharti};
178121461Sharti
179121461Sharti/************************************************************/
180121461Sharti/*
181121461Sharti * CONTROL MESSAGES
182121461Sharti */
183121461Shartistatic int
184121461Shartitext_status(node_p node, struct priv *priv, char *arg, u_int len)
185121461Sharti{
186121461Sharti	struct sbuf sbuf;
187121461Sharti
188121461Sharti	sbuf_new(&sbuf, arg, len, 0);
189121461Sharti
190121461Sharti	if (priv->upper)
191121461Sharti		sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n",
192121461Sharti		    NG_HOOK_NAME(priv->upper),
193121461Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
194121461Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
195121461Sharti	else
196121461Sharti		sbuf_printf(&sbuf, "upper hook: <not connected>\n");
197121461Sharti
198121461Sharti	if (priv->lower)
199121461Sharti		sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n",
200121461Sharti		    NG_HOOK_NAME(priv->lower),
201121461Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
202121461Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
203121461Sharti	else
204121461Sharti		sbuf_printf(&sbuf, "lower hook: <not connected>\n");
205121461Sharti
206121461Sharti	sbuf_printf(&sbuf, "sscf state: %s\n",
207123812Salfred	    priv->enabled == 0 ? "<disabled>" :
208121461Sharti	    sscfu_statename(sscfu_getstate(priv->sscf)));
209121461Sharti
210121461Sharti	sbuf_finish(&sbuf);
211121461Sharti	return (sbuf_len(&sbuf));
212121461Sharti}
213121461Sharti
214121461Shartistatic int
215121461Sharting_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook)
216121461Sharti{
217121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
218121461Sharti	struct ng_mesg *resp = NULL;
219121461Sharti	struct ng_mesg *msg;
220121461Sharti	int error = 0;
221121461Sharti
222121461Sharti	NGI_GET_MSG(item, msg);
223121461Sharti
224121461Sharti	switch (msg->header.typecookie) {
225121461Sharti
226121461Sharti	  case NGM_GENERIC_COOKIE:
227121461Sharti		switch (msg->header.cmd) {
228121461Sharti
229121461Sharti		  case NGM_TEXT_STATUS:
230121461Sharti			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
231121461Sharti			if (resp == NULL) {
232121461Sharti				error = ENOMEM;
233121461Sharti				break;
234121461Sharti			}
235121461Sharti			resp->header.arglen = text_status(node, priv,
236121461Sharti			    (char *)resp->data, resp->header.arglen) + 1;
237121461Sharti			break;
238121461Sharti
239121461Sharti		  default:
240121461Sharti			error = EINVAL;
241121461Sharti			break;
242121461Sharti		}
243121461Sharti		break;
244121461Sharti
245121461Sharti	  case NGM_SSCFU_COOKIE:
246121461Sharti		switch (msg->header.cmd) {
247121461Sharti
248121461Sharti		  case NGM_SSCFU_GETDEFPARAM:
249121461Sharti		    {
250121461Sharti			struct ng_sscfu_getdefparam *p;
251121461Sharti
252121461Sharti			if (msg->header.arglen != 0) {
253121461Sharti				error = EINVAL;
254121461Sharti				break;
255121461Sharti			}
256121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
257121461Sharti			if (resp == NULL) {
258121461Sharti				error = ENOMEM;
259121461Sharti				break;
260121461Sharti			}
261121461Sharti			p = (struct ng_sscfu_getdefparam *)resp->data;
262121461Sharti			p->mask = sscfu_getdefparam(&p->param);
263121461Sharti			break;
264121461Sharti		    }
265121461Sharti
266121461Sharti		  case NGM_SSCFU_ENABLE:
267121461Sharti			if (msg->header.arglen != 0) {
268121461Sharti				error = EINVAL;
269121461Sharti				break;
270121461Sharti			}
271121461Sharti			if (priv->enabled) {
272121461Sharti				error = EISCONN;
273121461Sharti				break;
274121461Sharti			}
275121461Sharti			priv->enabled = 1;
276121461Sharti			break;
277121461Sharti
278121461Sharti		  case NGM_SSCFU_DISABLE:
279121461Sharti			if (msg->header.arglen != 0) {
280121461Sharti				error = EINVAL;
281121461Sharti				break;
282121461Sharti			}
283121461Sharti			if (!priv->enabled) {
284121461Sharti				error = ENOTCONN;
285121461Sharti				break;
286121461Sharti			}
287121461Sharti			priv->enabled = 0;
288121461Sharti			sscfu_reset(priv->sscf);
289121461Sharti			break;
290121461Sharti
291121461Sharti		  case NGM_SSCFU_GETSTATE:
292121461Sharti			if (msg->header.arglen != 0) {
293121461Sharti				error = EINVAL;
294121461Sharti				break;
295121461Sharti			}
296121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
297121461Sharti			if(resp == NULL) {
298121461Sharti				error = ENOMEM;
299121461Sharti				break;
300121461Sharti			}
301121461Sharti			*(uint32_t *)resp->data =
302121461Sharti			    priv->enabled ? (sscfu_getstate(priv->sscf) + 1)
303121461Sharti			                  : 0;
304121461Sharti			break;
305121461Sharti
306121461Sharti		  case NGM_SSCFU_GETDEBUG:
307121461Sharti			if (msg->header.arglen != 0) {
308121461Sharti				error = EINVAL;
309121461Sharti				break;
310121461Sharti			}
311121461Sharti			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
312121461Sharti			if(resp == NULL) {
313121461Sharti				error = ENOMEM;
314121461Sharti				break;
315121461Sharti			}
316121461Sharti			*(uint32_t *)resp->data = sscfu_getdebug(priv->sscf);
317121461Sharti			break;
318121461Sharti
319121461Sharti		  case NGM_SSCFU_SETDEBUG:
320121461Sharti			if (msg->header.arglen != sizeof(uint32_t)) {
321121461Sharti				error = EINVAL;
322121461Sharti				break;
323121461Sharti			}
324121461Sharti			sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data);
325121461Sharti			break;
326121461Sharti
327121461Sharti		  default:
328121461Sharti			error = EINVAL;
329121461Sharti			break;
330121461Sharti		}
331121461Sharti		break;
332121461Sharti
333121461Sharti	  default:
334121461Sharti		error = EINVAL;
335121461Sharti		break;
336121461Sharti	}
337121461Sharti
338121461Sharti	NG_RESPOND_MSG(error, node, item, resp);
339121461Sharti	NG_FREE_MSG(msg);
340121461Sharti
341121461Sharti	return (error);
342121461Sharti}
343121461Sharti
344121461Sharti/************************************************************/
345121461Sharti/*
346121461Sharti * HOOK MANAGEMENT
347121461Sharti */
348121461Shartistatic int
349121461Sharting_sscfu_newhook(node_p node, hook_p hook, const char *name)
350121461Sharti{
351121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
352121461Sharti
353121461Sharti	if (strcmp(name, "upper") == 0)
354121461Sharti		priv->upper = hook;
355121461Sharti	else if (strcmp(name, "lower") == 0) {
356121461Sharti		priv->lower = hook;
357121461Sharti		NG_HOOK_SET_RCVDATA(hook, ng_sscfu_rcvlower);
358121461Sharti	} else
359121461Sharti		return (EINVAL);
360121461Sharti	return (0);
361121461Sharti}
362121461Sharti
363121461Shartistatic int
364121461Sharting_sscfu_disconnect(hook_p hook)
365121461Sharti{
366121461Sharti	node_p node = NG_HOOK_NODE(hook);
367121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
368121461Sharti
369121461Sharti	if (hook == priv->upper)
370121461Sharti		priv->upper = NULL;
371121461Sharti	else if (hook == priv->lower)
372121461Sharti		priv->lower = NULL;
373121461Sharti	else {
374121461Sharti		log(LOG_ERR, "bogus hook");
375121461Sharti		return (EINVAL);
376121461Sharti	}
377121461Sharti
378121461Sharti	if (NG_NODE_NUMHOOKS(node) == 0) {
379121461Sharti		if (NG_NODE_IS_VALID(node))
380121461Sharti			ng_rmnode_self(node);
381121461Sharti	} else {
382121461Sharti		/*
383121461Sharti		 * Because there are no timeouts reset the protocol
384121461Sharti		 * if the lower layer is disconnected.
385121461Sharti		 */
386121461Sharti		if (priv->lower == NULL &&
387121461Sharti		    priv->enabled &&
388121461Sharti		    sscfu_getstate(priv->sscf) != SSCFU_RELEASED)
389121461Sharti			sscfu_reset(priv->sscf);
390121461Sharti	}
391121461Sharti	return (0);
392121461Sharti}
393121461Sharti
394121461Sharti/************************************************************/
395121461Sharti/*
396121461Sharti * DATA
397121461Sharti */
398121461Shartistatic int
399121461Sharting_sscfu_rcvupper(hook_p hook, item_p item)
400121461Sharti{
401121461Sharti	node_p node = NG_HOOK_NODE(hook);
402121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
403121461Sharti	struct mbuf *m;
404121461Sharti	struct sscfu_arg a;
405121461Sharti
406121461Sharti	if (!priv->enabled || priv->lower == NULL) {
407121461Sharti		NG_FREE_ITEM(item);
408121461Sharti		return (0);
409121461Sharti	}
410121461Sharti
411121461Sharti	NGI_GET_M(item, m);
412121461Sharti	NG_FREE_ITEM(item);
413121461Sharti
414121461Sharti	if (!(m->m_flags & M_PKTHDR)) {
415121461Sharti		printf("no pkthdr\n");
416121461Sharti		m_freem(m);
417121461Sharti		return (EINVAL);
418121461Sharti	}
419121461Sharti	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
420121461Sharti		return (ENOMEM);
421121461Sharti	bcopy((caddr_t)mtod(m, struct sscfu_arg *), &a, sizeof(a));
422121461Sharti	m_adj(m, sizeof(a));
423121461Sharti
424121461Sharti	return (sscfu_saalsig(priv->sscf, a.sig, m));
425121461Sharti}
426121461Sharti
427121461Shartistatic void
428121461Shartisscfu_send_upper(struct sscfu *sscf, void *p, enum saal_sig sig, struct mbuf *m)
429121461Sharti{
430121461Sharti	node_p node = (node_p)p;
431121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
432121461Sharti	int error;
433121461Sharti	struct sscfu_arg *a;
434121461Sharti
435121461Sharti	if (priv->upper == NULL) {
436121461Sharti		if (m != NULL)
437121461Sharti			m_freem(m);
438121461Sharti		return;
439121461Sharti	}
440121461Sharti	if (m == NULL) {
441121461Sharti		MGETHDR(m, M_NOWAIT, MT_DATA);
442121461Sharti		if (m == NULL)
443121461Sharti			return;
444121461Sharti		m->m_len = sizeof(struct sscfu_arg);
445121461Sharti		m->m_pkthdr.len = m->m_len;
446121461Sharti	} else {
447121461Sharti		M_PREPEND(m, sizeof(struct sscfu_arg), M_NOWAIT);
448121461Sharti		if (m == NULL)
449121461Sharti			return;
450121461Sharti	}
451121461Sharti	a = mtod(m, struct sscfu_arg *);
452121461Sharti	a->sig = sig;
453121461Sharti
454121461Sharti	NG_SEND_DATA_ONLY(error, priv->upper, m);
455121461Sharti}
456121461Sharti
457121461Shartistatic int
458121461Sharting_sscfu_rcvlower(hook_p hook, item_p item)
459121461Sharti{
460121461Sharti	node_p node = NG_HOOK_NODE(hook);
461121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
462121461Sharti	struct mbuf *m;
463121461Sharti	struct sscop_arg a;
464121461Sharti
465121461Sharti	if (!priv->enabled || priv->upper == NULL) {
466121461Sharti		NG_FREE_ITEM(item);
467121461Sharti		return (0);
468121461Sharti	}
469121461Sharti
470121461Sharti	NGI_GET_M(item, m);
471121461Sharti	NG_FREE_ITEM(item);
472121461Sharti
473121461Sharti	if (!(m->m_flags & M_PKTHDR)) {
474121461Sharti		printf("no pkthdr\n");
475121461Sharti		m_freem(m);
476121461Sharti		return (EINVAL);
477121461Sharti	}
478121461Sharti
479121461Sharti	/*
480121461Sharti	 * Strip of the SSCOP header.
481121461Sharti	 */
482121461Sharti	if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL)
483121461Sharti		return (ENOMEM);
484121461Sharti	bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a));
485121461Sharti	m_adj(m, sizeof(a));
486121461Sharti
487121461Sharti	sscfu_input(priv->sscf, a.sig, m, a.arg);
488121461Sharti
489121461Sharti	return (0);
490121461Sharti}
491121461Sharti
492121461Shartistatic void
493121461Shartisscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig,
494121461Sharti    struct mbuf *m, u_int arg)
495121461Sharti{
496121461Sharti	node_p node = (node_p)p;
497121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
498121461Sharti	int error;
499121461Sharti	struct sscop_arg *a;
500121461Sharti
501121461Sharti	if (priv->lower == NULL) {
502121461Sharti		if (m != NULL)
503121461Sharti			m_freem(m);
504121461Sharti		return;
505121461Sharti	}
506121461Sharti	if (m == NULL) {
507121461Sharti		MGETHDR(m, M_NOWAIT, MT_DATA);
508121461Sharti		if (m == NULL)
509121461Sharti			return;
510121461Sharti		m->m_len = sizeof(struct sscop_arg);
511121461Sharti		m->m_pkthdr.len = m->m_len;
512121461Sharti	} else {
513121461Sharti		M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT);
514121461Sharti		if (m == NULL)
515121461Sharti			return;
516121461Sharti	}
517121461Sharti	a = mtod(m, struct sscop_arg *);
518121461Sharti	a->sig = sig;
519121461Sharti	a->arg = arg;
520121461Sharti
521121461Sharti	NG_SEND_DATA_ONLY(error, priv->lower, m);
522121461Sharti}
523121461Sharti
524121461Sharti/*
525121461Sharti * Window is handled by ng_sscop so make this a NOP.
526121461Sharti */
527121461Shartistatic void
528121461Shartisscfu_window(struct sscfu *sscfu, void *arg, u_int w)
529121461Sharti{
530121461Sharti}
531121461Sharti
532121461Sharti/************************************************************/
533121461Sharti/*
534121461Sharti * NODE MANAGEMENT
535121461Sharti */
536121461Shartistatic int
537121461Sharting_sscfu_constructor(node_p node)
538121461Sharti{
539121461Sharti	struct priv *priv;
540121461Sharti
541220768Sglebius	priv = malloc(sizeof(*priv), M_NG_SSCFU, M_WAITOK | M_ZERO);
542121461Sharti
543121461Sharti	if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) {
544121461Sharti		free(priv, M_NG_SSCFU);
545121461Sharti		return (ENOMEM);
546121461Sharti	}
547121461Sharti
548121461Sharti	NG_NODE_SET_PRIVATE(node, priv);
549121461Sharti
550121461Sharti	return (0);
551121461Sharti}
552121461Sharti
553121461Shartistatic int
554121461Sharting_sscfu_shutdown(node_p node)
555121461Sharti{
556121461Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
557121461Sharti
558121461Sharti	sscfu_destroy(priv->sscf);
559121461Sharti
560121461Sharti	free(priv, M_NG_SSCFU);
561121461Sharti	NG_NODE_SET_PRIVATE(node, NULL);
562121461Sharti
563121461Sharti	NG_NODE_UNREF(node);
564121461Sharti
565121461Sharti	return (0);
566121461Sharti}
567121461Sharti
568121461Shartistatic void
569121461Shartisscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...)
570121461Sharti{
571121461Sharti	va_list ap;
572121461Sharti
573121461Sharti	va_start(ap, fmt);
574121461Sharti	printf("sscfu(%p): ", sscfu);
575121461Sharti	vprintf(fmt, ap);
576121461Sharti	va_end(ap);
577121461Sharti	printf("\n");
578121461Sharti}
579121461Sharti
580121461Sharti/************************************************************/
581121461Sharti/*
582121461Sharti * INITIALISATION
583121461Sharti */
584121461Sharti/*
585121461Sharti * Loading and unloading of node type
586121461Sharti */
587121461Shartistatic int
588121461Sharting_sscfu_mod_event(module_t mod, int event, void *data)
589121461Sharti{
590121461Sharti	int s;
591121461Sharti	int error = 0;
592121461Sharti
593121461Sharti	s = splnet();
594121461Sharti	switch (event) {
595121461Sharti
596121461Sharti	  case MOD_LOAD:
597121461Sharti		break;
598121461Sharti
599121461Sharti	  case MOD_UNLOAD:
600121461Sharti		break;
601121461Sharti
602121461Sharti	  default:
603121461Sharti		error = EOPNOTSUPP;
604121461Sharti		break;
605121461Sharti	}
606121461Sharti	splx(s);
607121461Sharti	return (error);
608121461Sharti}
609