1139823Simp/*-
2122219Sharti * Copyright (c) 2001-2003
3122219Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122219Sharti * 	All rights reserved.
5122219Sharti *
6122219Sharti * Author: Hartmut Brandt <harti@freebsd.org>
7122219Sharti *
8122219Sharti * Redistribution and use in source and binary forms, with or without
9122219Sharti * modification, are permitted provided that the following conditions
10122219Sharti * are met:
11122219Sharti * 1. Redistributions of source code must retain the above copyright
12122219Sharti *    notice, this list of conditions and the following disclaimer.
13122219Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122219Sharti *    notice, this list of conditions and the following disclaimer in the
15122219Sharti *    documentation and/or other materials provided with the distribution.
16122219Sharti *
17122219Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18122219Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19122219Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20122219Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21122219Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22122219Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23122219Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24122219Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25122219Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26122219Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27122219Sharti * SUCH DAMAGE.
28122219Sharti *
29122219Sharti * Netgraph module for ATM-Forum UNI 4.0 signalling
30122219Sharti */
31122219Sharti
32122219Sharti#include <sys/cdefs.h>
33122219Sharti__FBSDID("$FreeBSD$");
34122219Sharti
35122219Sharti#include <sys/param.h>
36122219Sharti#include <sys/systm.h>
37122219Sharti#include <sys/kernel.h>
38122219Sharti#include <sys/malloc.h>
39122219Sharti#include <sys/mbuf.h>
40122219Sharti#include <sys/errno.h>
41122219Sharti#include <sys/syslog.h>
42122219Sharti#include <sys/socket.h>
43122219Sharti#include <sys/socketvar.h>
44122219Sharti#include <sys/callout.h>
45122219Sharti#include <sys/sbuf.h>
46122219Sharti#include <machine/stdarg.h>
47122219Sharti
48122219Sharti#include <netgraph/ng_message.h>
49122219Sharti#include <netgraph/netgraph.h>
50122219Sharti#include <netgraph/ng_parse.h>
51122219Sharti#include <netnatm/unimsg.h>
52122219Sharti#include <netnatm/msg/unistruct.h>
53122219Sharti#include <netgraph/atm/ngatmbase.h>
54122219Sharti#include <netnatm/saal/sscopdef.h>
55122219Sharti#include <netnatm/saal/sscfudef.h>
56122219Sharti#include <netgraph/atm/uni/ng_uni_cust.h>
57122219Sharti#include <netnatm/sig/uni.h>
58122219Sharti#include <netnatm/sig/unisig.h>
59122219Sharti#include <netgraph/atm/ng_sscop.h>
60122219Sharti#include <netgraph/atm/ng_sscfu.h>
61122219Sharti#include <netgraph/atm/ng_uni.h>
62122219Sharti
63227293Sedstatic MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
64227293Sedstatic MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data");
65122219Sharti
66122219ShartiMODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
67122219Sharti
68122219Sharti/*
69122219Sharti * Private node data
70122219Sharti */
71122219Shartistruct priv {
72122219Sharti	hook_p	upper;
73122219Sharti	hook_p	lower;
74122219Sharti	struct uni *uni;
75122219Sharti	int	enabled;
76122219Sharti};
77122219Sharti
78122219Sharti/* UNI CONFIG MASK */
79122219Shartistatic const struct ng_parse_struct_field ng_uni_config_mask_type_info[] =
80122219Sharti	NGM_UNI_CONFIG_MASK_INFO;
81122219Shartistatic const struct ng_parse_type ng_uni_config_mask_type = {
82122219Sharti	&ng_parse_struct_type,
83122219Sharti	ng_uni_config_mask_type_info
84122219Sharti};
85122219Sharti
86122219Sharti/* UNI_CONFIG */
87122219Shartistatic const struct ng_parse_struct_field ng_uni_config_type_info[] =
88122219Sharti	NGM_UNI_CONFIG_INFO;
89122219Shartistatic const struct ng_parse_type ng_uni_config_type = {
90122219Sharti	&ng_parse_struct_type,
91122219Sharti	ng_uni_config_type_info
92122219Sharti};
93122219Sharti
94122219Sharti/* SET CONFIG */
95122219Shartistatic const struct ng_parse_struct_field ng_uni_set_config_type_info[] =
96122219Sharti	NGM_UNI_SET_CONFIG_INFO;
97122219Shartistatic const struct ng_parse_type ng_uni_set_config_type = {
98122219Sharti	&ng_parse_struct_type,
99122219Sharti	ng_uni_set_config_type_info
100122219Sharti};
101122219Sharti
102122219Sharti/*
103122219Sharti * Parse DEBUG
104122219Sharti */
105122219Shartistatic const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info =
106122219Sharti    NGM_UNI_DEBUGLEVEL_INFO;
107122219Shartistatic const struct ng_parse_type ng_uni_debuglevel_type = {
108122219Sharti	&ng_parse_fixedarray_type,
109122219Sharti	&ng_uni_debuglevel_type_info
110122219Sharti};
111122219Shartistatic const struct ng_parse_struct_field ng_uni_debug_type_info[] =
112122219Sharti    NGM_UNI_DEBUG_INFO;
113122219Shartistatic const struct ng_parse_type ng_uni_debug_type = {
114122219Sharti	&ng_parse_struct_type,
115122219Sharti	ng_uni_debug_type_info
116122219Sharti};
117122219Sharti
118122219Sharti/*
119122219Sharti * Command list
120122219Sharti */
121122219Shartistatic const struct ng_cmdlist ng_uni_cmdlist[] = {
122122219Sharti	{
123122219Sharti	  NGM_UNI_COOKIE,
124122219Sharti	  NGM_UNI_GETDEBUG,
125122219Sharti	  "getdebug",
126122219Sharti	  NULL,
127122219Sharti	  &ng_uni_debug_type
128122219Sharti	},
129122219Sharti	{
130122219Sharti	  NGM_UNI_COOKIE,
131122219Sharti	  NGM_UNI_SETDEBUG,
132122219Sharti	  "setdebug",
133122219Sharti	  &ng_uni_debug_type,
134122219Sharti	  NULL
135122219Sharti	},
136122219Sharti	{
137122219Sharti	  NGM_UNI_COOKIE,
138122219Sharti	  NGM_UNI_GET_CONFIG,
139122219Sharti	  "get_config",
140122219Sharti	  NULL,
141122219Sharti	  &ng_uni_config_type
142122219Sharti	},
143122219Sharti	{
144122219Sharti	  NGM_UNI_COOKIE,
145122219Sharti	  NGM_UNI_SET_CONFIG,
146122219Sharti	  "set_config",
147122219Sharti	  &ng_uni_set_config_type,
148122219Sharti	  &ng_uni_config_mask_type,
149122219Sharti	},
150122219Sharti	{
151122219Sharti	  NGM_UNI_COOKIE,
152122219Sharti	  NGM_UNI_ENABLE,
153122219Sharti	  "enable",
154122219Sharti	  NULL,
155122219Sharti	  NULL,
156122219Sharti	},
157122219Sharti	{
158122219Sharti	  NGM_UNI_COOKIE,
159122219Sharti	  NGM_UNI_DISABLE,
160122219Sharti	  "disable",
161122219Sharti	  NULL,
162122219Sharti	  NULL,
163122219Sharti	},
164122219Sharti	{
165122219Sharti	  NGM_UNI_COOKIE,
166122219Sharti	  NGM_UNI_GETSTATE,
167122219Sharti	  "getstate",
168122219Sharti	  NULL,
169122219Sharti	  &ng_parse_uint32_type
170122219Sharti	},
171122219Sharti	{ 0 }
172122219Sharti};
173122219Sharti
174122219Sharti/*
175122219Sharti * Netgraph module data
176122219Sharti */
177122219Shartistatic ng_constructor_t ng_uni_constructor;
178122219Shartistatic ng_shutdown_t	ng_uni_shutdown;
179122219Shartistatic ng_rcvmsg_t	ng_uni_rcvmsg;
180122219Shartistatic ng_newhook_t	ng_uni_newhook;
181122219Shartistatic ng_disconnect_t	ng_uni_disconnect;
182122219Shartistatic ng_rcvdata_t	ng_uni_rcvlower;
183122219Shartistatic ng_rcvdata_t	ng_uni_rcvupper;
184122219Sharti
185122219Shartistatic int ng_uni_mod_event(module_t, int, void *);
186122219Sharti
187122219Shartistatic struct ng_type ng_uni_typestruct = {
188129823Sjulian	.version =	NG_ABI_VERSION,
189129823Sjulian	.name =		NG_UNI_NODE_TYPE,
190129823Sjulian	.mod_event =	ng_uni_mod_event,
191129823Sjulian	.constructor =	ng_uni_constructor,
192129823Sjulian	.rcvmsg =	ng_uni_rcvmsg,
193129823Sjulian	.shutdown =	ng_uni_shutdown,
194129823Sjulian	.newhook =	ng_uni_newhook,
195129823Sjulian	.rcvdata =	ng_uni_rcvlower,
196129823Sjulian	.disconnect =	ng_uni_disconnect,
197129823Sjulian	.cmdlist =	ng_uni_cmdlist,
198122219Sharti};
199122219ShartiNETGRAPH_INIT(uni, &ng_uni_typestruct);
200122219Sharti
201122219Shartistatic void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
202122219Sharti    struct uni_msg *);
203122219Shartistatic void uni_saal_output(struct uni *, void *, enum saal_sig,
204122219Sharti    struct uni_msg *);
205122219Shartistatic void uni_verbose(struct uni *, void *, u_int, const char *, ...)
206122219Sharti    __printflike(4, 5);
207122219Shartistatic void uni_do_status(struct uni *, void *, void *, const char *, ...)
208122219Sharti    __printflike(4, 5);
209122219Sharti
210122219Shartistatic const struct uni_funcs uni_funcs = {
211122219Sharti	uni_uni_output,
212122219Sharti	uni_saal_output,
213122219Sharti	uni_verbose,
214122219Sharti	uni_do_status
215122219Sharti};
216122219Sharti
217122219Sharti/************************************************************/
218122219Sharti/*
219122219Sharti * NODE MANAGEMENT
220122219Sharti */
221122219Shartistatic int
222122219Sharting_uni_constructor(node_p node)
223122219Sharti{
224122219Sharti	struct priv *priv;
225122219Sharti
226220768Sglebius	priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
227122219Sharti
228122219Sharti	if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
229122219Sharti		free(priv, M_NG_UNI);
230122219Sharti		return (ENOMEM);
231122219Sharti	}
232122219Sharti
233122219Sharti	NG_NODE_SET_PRIVATE(node, priv);
234122219Sharti	NG_NODE_FORCE_WRITER(node);
235122219Sharti
236122219Sharti	return (0);
237122219Sharti}
238122219Sharti
239122219Shartistatic int
240122219Sharting_uni_shutdown(node_p node)
241122219Sharti{
242122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
243122219Sharti
244122219Sharti	uni_destroy(priv->uni);
245122219Sharti
246122219Sharti	free(priv, M_NG_UNI);
247122219Sharti	NG_NODE_SET_PRIVATE(node, NULL);
248122219Sharti
249122219Sharti	NG_NODE_UNREF(node);
250122219Sharti
251122219Sharti	return (0);
252122219Sharti}
253122219Sharti
254122219Sharti/************************************************************/
255122219Sharti/*
256122219Sharti * CONTROL MESSAGES
257122219Sharti */
258122219Shartistatic void
259122219Shartiuni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
260122219Sharti{
261122219Sharti	va_list ap;
262122219Sharti
263122219Sharti	va_start(ap, fmt);
264122219Sharti	sbuf_printf(sbuf, fmt, ap);
265122219Sharti	va_end(ap);
266122219Sharti}
267122219Sharti
268122219Shartistatic int
269122219Shartitext_status(node_p node, struct priv *priv, char *buf, u_int len)
270122219Sharti{
271122219Sharti	struct sbuf sbuf;
272122219Sharti	u_int f;
273122219Sharti
274122219Sharti	sbuf_new(&sbuf, buf, len, 0);
275122219Sharti
276122219Sharti	if (priv->lower != NULL)
277122219Sharti		sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
278122219Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
279122219Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
280122219Sharti	else
281122219Sharti		sbuf_printf(&sbuf, "lower hook: <not connected>\n");
282122219Sharti
283122219Sharti	if (priv->upper != NULL)
284122219Sharti		sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
285122219Sharti		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
286122219Sharti		    NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
287122219Sharti	else
288122219Sharti		sbuf_printf(&sbuf, "upper hook: <not connected>\n");
289122219Sharti
290122219Sharti	sbuf_printf(&sbuf, "debugging:");
291122219Sharti	for (f = 0; f < UNI_MAXFACILITY; f++)
292122219Sharti		if (uni_get_debug(priv->uni, f) != 0)
293122219Sharti			sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
294122219Sharti			    uni_get_debug(priv->uni, f));
295122219Sharti	sbuf_printf(&sbuf, "\n");
296122219Sharti
297122219Sharti	if (priv->uni)
298122219Sharti		uni_status(priv->uni, &sbuf);
299122219Sharti
300122219Sharti	sbuf_finish(&sbuf);
301122219Sharti	return (sbuf_len(&sbuf));
302122219Sharti}
303122219Sharti
304122219Shartistatic int
305122219Sharting_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
306122219Sharti{
307122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
308122219Sharti	struct ng_mesg *resp = NULL;
309122219Sharti	struct ng_mesg *msg;
310122219Sharti	int error = 0;
311122219Sharti	u_int i;
312122219Sharti
313122219Sharti	NGI_GET_MSG(item, msg);
314122219Sharti
315122219Sharti	switch (msg->header.typecookie) {
316122219Sharti
317122219Sharti	  case NGM_GENERIC_COOKIE:
318122219Sharti		switch (msg->header.cmd) {
319122219Sharti
320122219Sharti		  case NGM_TEXT_STATUS:
321122219Sharti			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
322122219Sharti			if (resp == NULL) {
323122219Sharti				error = ENOMEM;
324122219Sharti				break;
325122219Sharti			}
326122219Sharti
327122219Sharti			resp->header.arglen = text_status(node, priv,
328122219Sharti			    (char *)resp->data, resp->header.arglen) + 1;
329122219Sharti			break;
330122219Sharti
331122219Sharti		  default:
332122219Sharti			error = EINVAL;
333122219Sharti			break;
334122219Sharti		}
335122219Sharti		break;
336122219Sharti
337122219Sharti	  case NGM_UNI_COOKIE:
338122219Sharti		switch (msg->header.cmd) {
339122219Sharti
340122219Sharti		  case NGM_UNI_SETDEBUG:
341122219Sharti		    {
342122219Sharti			struct ngm_uni_debug *arg;
343122219Sharti
344122219Sharti			if (msg->header.arglen > sizeof(*arg)) {
345122219Sharti				error = EINVAL;
346122219Sharti				break;
347122219Sharti			}
348122219Sharti			arg = (struct ngm_uni_debug *)msg->data;
349122219Sharti			for (i = 0; i < UNI_MAXFACILITY; i++)
350122219Sharti				uni_set_debug(priv->uni, i, arg->level[i]);
351122219Sharti			break;
352122219Sharti		    }
353122219Sharti
354122219Sharti		  case NGM_UNI_GETDEBUG:
355122219Sharti		    {
356122219Sharti			struct ngm_uni_debug *arg;
357122219Sharti
358122219Sharti			NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
359122219Sharti			if(resp == NULL) {
360122219Sharti				error = ENOMEM;
361122219Sharti				break;
362122219Sharti			}
363122219Sharti			arg = (struct ngm_uni_debug *)resp->data;
364122219Sharti			for (i = 0; i < UNI_MAXFACILITY; i++)
365122219Sharti				arg->level[i] = uni_get_debug(priv->uni, i);
366122219Sharti			break;
367122219Sharti		    }
368122219Sharti
369122219Sharti		  case NGM_UNI_GET_CONFIG:
370122219Sharti		    {
371122219Sharti			struct uni_config *config;
372122219Sharti
373122219Sharti			if (msg->header.arglen != 0) {
374122219Sharti				error = EINVAL;
375122219Sharti				break;
376122219Sharti			}
377122219Sharti			NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
378122219Sharti			if (resp == NULL) {
379122219Sharti				error = ENOMEM;
380122219Sharti				break;
381122219Sharti			}
382122219Sharti			config = (struct uni_config *)resp->data;
383122219Sharti			uni_get_config(priv->uni, config);
384122219Sharti
385122219Sharti			break;
386122219Sharti		    }
387122219Sharti
388122219Sharti		  case NGM_UNI_SET_CONFIG:
389122219Sharti		    {
390122219Sharti			struct ngm_uni_set_config *arg;
391122219Sharti			struct ngm_uni_config_mask *mask;
392122219Sharti
393122219Sharti			if (msg->header.arglen != sizeof(*arg)) {
394122219Sharti				error = EINVAL;
395122219Sharti				break;
396122219Sharti			}
397122219Sharti			arg = (struct ngm_uni_set_config *)msg->data;
398122219Sharti
399122219Sharti			NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
400122219Sharti			if (resp == NULL) {
401122219Sharti				error = ENOMEM;
402122219Sharti				break;
403122219Sharti			}
404122219Sharti			mask = (struct ngm_uni_config_mask *)resp->data;
405122219Sharti
406122219Sharti			*mask = arg->mask;
407122219Sharti
408122219Sharti			uni_set_config(priv->uni, &arg->config,
409122219Sharti			    &mask->mask, &mask->popt_mask, &mask->option_mask);
410122219Sharti
411122219Sharti			break;
412122219Sharti		    }
413122219Sharti
414122219Sharti		  case NGM_UNI_ENABLE:
415122219Sharti			if (msg->header.arglen != 0) {
416122219Sharti				error = EINVAL;
417122219Sharti				break;
418122219Sharti			}
419122219Sharti			if (priv->enabled) {
420122219Sharti				error = EISCONN;
421122219Sharti				break;
422122219Sharti			}
423122219Sharti			priv->enabled = 1;
424122219Sharti			break;
425122219Sharti
426122219Sharti		  case NGM_UNI_DISABLE:
427122219Sharti			if (msg->header.arglen != 0) {
428122219Sharti				error = EINVAL;
429122219Sharti				break;
430122219Sharti			}
431122219Sharti			if (!priv->enabled) {
432122219Sharti				error = ENOTCONN;
433122219Sharti				break;
434122219Sharti			}
435122219Sharti			priv->enabled = 0;
436122219Sharti			uni_reset(priv->uni);
437122219Sharti			break;
438122219Sharti
439122219Sharti		  case NGM_UNI_GETSTATE:
440122219Sharti			if (msg->header.arglen != 0) {
441122219Sharti				error = EINVAL;
442122219Sharti				break;
443122219Sharti			}
444122219Sharti			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
445122219Sharti			if(resp == NULL) {
446122219Sharti				error = ENOMEM;
447122219Sharti				break;
448122219Sharti			}
449122219Sharti			*(u_int32_t *)resp->data =
450122219Sharti			    priv->enabled ? (uni_getcustate(priv->uni) + 1)
451122219Sharti			                  : 0;
452122219Sharti			break;
453122219Sharti
454122219Sharti		  default:
455122219Sharti			error = EINVAL;
456122219Sharti			break;
457122219Sharti		}
458122219Sharti		break;
459122219Sharti
460122219Sharti	  default:
461122219Sharti		error = EINVAL;
462122219Sharti		break;
463122219Sharti	}
464122219Sharti
465122219Sharti	NG_RESPOND_MSG(error, node, item, resp);
466122219Sharti	NG_FREE_MSG(msg);
467122219Sharti	return (error);
468122219Sharti}
469122219Sharti
470122219Sharti/************************************************************/
471122219Sharti/*
472122219Sharti * HOOK MANAGEMENT
473122219Sharti */
474122219Shartistatic int
475122219Sharting_uni_newhook(node_p node, hook_p hook, const char *name)
476122219Sharti{
477122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
478122219Sharti
479122219Sharti	if (strcmp(name, "lower") == 0) {
480122219Sharti		priv->lower = hook;
481122219Sharti	} else if(strcmp(name, "upper") == 0) {
482122219Sharti		priv->upper = hook;
483122219Sharti		NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
484122219Sharti	} else
485122219Sharti		return EINVAL;
486122219Sharti
487122219Sharti	return 0;
488122219Sharti}
489122219Sharti
490122219Shartistatic int
491122219Sharting_uni_disconnect(hook_p hook)
492122219Sharti{
493122219Sharti	node_p node = NG_HOOK_NODE(hook);
494122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
495122219Sharti
496122219Sharti	if(hook == priv->lower)
497122219Sharti		priv->lower = NULL;
498122219Sharti	else if(hook == priv->upper)
499122219Sharti		priv->upper = NULL;
500122219Sharti	else
501148915Sobrien		printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
502122219Sharti
503122219Sharti	if (NG_NODE_NUMHOOKS(node) == 0) {
504122219Sharti		if (NG_NODE_IS_VALID(node))
505122219Sharti			ng_rmnode_self(node);
506122219Sharti	}
507122219Sharti
508122219Sharti	return (0);
509122219Sharti}
510122219Sharti
511122219Sharti/************************************************************/
512122219Sharti/*
513122219Sharti * DATA
514122219Sharti */
515122219Sharti/*
516122219Sharti * Receive signal from USER.
517122219Sharti *
518122219Sharti * Repackage the data into one large buffer.
519122219Sharti */
520122219Shartistatic int
521122219Sharting_uni_rcvupper(hook_p hook, item_p item)
522122219Sharti{
523122219Sharti	node_p node = NG_HOOK_NODE(hook);
524122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
525122219Sharti	struct mbuf *m;
526122219Sharti	struct uni_arg arg;
527122219Sharti	struct uni_msg *msg;
528122219Sharti	int error;
529122219Sharti
530122219Sharti	if (!priv->enabled) {
531122219Sharti		NG_FREE_ITEM(item);
532122219Sharti		return (ENOTCONN);
533122219Sharti	}
534122219Sharti
535122219Sharti	NGI_GET_M(item, m);
536122219Sharti	NG_FREE_ITEM(item);
537122219Sharti
538122219Sharti	if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
539122219Sharti		m_freem(m);
540122219Sharti		return (error);
541122219Sharti	}
542122219Sharti	m_freem(m);
543122219Sharti
544122219Sharti	if (uni_msg_len(msg) < sizeof(arg)) {
545148915Sobrien		printf("%s: packet too short\n", __func__);
546122219Sharti		uni_msg_destroy(msg);
547122219Sharti		return (EINVAL);
548122219Sharti	}
549122219Sharti
550122219Sharti	bcopy(msg->b_rptr, &arg, sizeof(arg));
551122219Sharti	msg->b_rptr += sizeof(arg);
552122219Sharti
553122219Sharti	if (arg.sig >= UNIAPI_MAXSIG) {
554148915Sobrien		printf("%s: bogus signal\n", __func__);
555122219Sharti		uni_msg_destroy(msg);
556122219Sharti		return (EINVAL);
557122219Sharti	}
558122219Sharti	uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
559122219Sharti	uni_work(priv->uni);
560122219Sharti
561122219Sharti	return (0);
562122219Sharti}
563122219Sharti
564122219Sharti
565122219Sharti/*
566122219Sharti * Upper layer signal from UNI
567122219Sharti */
568122219Shartistatic void
569122219Shartiuni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
570122219Sharti    struct uni_msg *msg)
571122219Sharti{
572122219Sharti	node_p node = (node_p)varg;
573122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
574122219Sharti	struct mbuf *m;
575122219Sharti	struct uni_arg arg;
576122219Sharti	int error;
577122219Sharti
578122219Sharti	if (priv->upper == NULL) {
579122219Sharti		if (msg != NULL)
580122219Sharti			uni_msg_destroy(msg);
581122219Sharti		return;
582122219Sharti	}
583122219Sharti	arg.sig = sig;
584122219Sharti	arg.cookie = cookie;
585122219Sharti
586122219Sharti	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
587122219Sharti	if (msg != NULL)
588122219Sharti		uni_msg_destroy(msg);
589122219Sharti	if (m == NULL)
590122219Sharti		return;
591122219Sharti
592122219Sharti	NG_SEND_DATA_ONLY(error, priv->upper, m);
593122219Sharti}
594122219Sharti
595122219Sharti
596122219Shartistatic void
597122219Shartidump_uni_msg(struct uni_msg *msg)
598122219Sharti{
599122219Sharti	u_int pos;
600122219Sharti
601122219Sharti	for (pos = 0; pos < uni_msg_len(msg); pos++) {
602122219Sharti		if (pos % 16 == 0)
603122219Sharti			printf("%06o ", pos);
604122219Sharti		if (pos % 16 == 8)
605122219Sharti			printf("  ");
606122219Sharti		printf(" %02x", msg->b_rptr[pos]);
607122219Sharti		if (pos % 16 == 15)
608122219Sharti			printf("\n");
609122219Sharti	}
610122219Sharti	if (pos % 16 != 0)
611122219Sharti		printf("\n");
612122219Sharti}
613122219Sharti
614122219Sharti
615122219Sharti/*
616122219Sharti * Dump a SAAL signal in either direction
617122219Sharti */
618122219Shartistatic void
619122219Shartidump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
620122219Sharti{
621122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
622122219Sharti
623122219Sharti	printf("signal %s SAAL: ", to ? "to" : "from");
624122219Sharti
625122219Sharti	switch (sig) {
626122219Sharti
627122219Sharti#define D(S) case S: printf("%s", #S); break
628122219Sharti
629122219Sharti	D(SAAL_ESTABLISH_request);
630122219Sharti	D(SAAL_ESTABLISH_indication);
631122219Sharti	D(SAAL_ESTABLISH_confirm);
632122219Sharti	D(SAAL_RELEASE_request);
633122219Sharti	D(SAAL_RELEASE_confirm);
634122219Sharti	D(SAAL_RELEASE_indication);
635122219Sharti	D(SAAL_DATA_request);
636122219Sharti	D(SAAL_DATA_indication);
637122219Sharti	D(SAAL_UDATA_request);
638122219Sharti	D(SAAL_UDATA_indication);
639122219Sharti
640122219Sharti#undef D
641122219Sharti	  default:
642122219Sharti		printf("sig=%d", sig); break;
643122219Sharti	}
644122219Sharti	if (msg != NULL) {
645122219Sharti		printf(" data=%zu\n", uni_msg_len(msg));
646122219Sharti		if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
647122219Sharti			dump_uni_msg(msg);
648122219Sharti	} else
649122219Sharti		printf("\n");
650122219Sharti}
651122219Sharti
652122219Sharti/*
653122219Sharti * Receive signal from SSCOP.
654122219Sharti *
655122219Sharti * If this is a data signal, repackage the data into one large buffer.
656122219Sharti * UNI shouldn't be the bottleneck in a system and this greatly simplifies
657122219Sharti * parsing in UNI.
658122219Sharti */
659122219Shartistatic int
660122219Sharting_uni_rcvlower(hook_p hook __unused, item_p item)
661122219Sharti{
662122219Sharti	node_p node = NG_HOOK_NODE(hook);
663122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
664122219Sharti	struct mbuf *m;
665122219Sharti	struct sscfu_arg arg;
666122219Sharti	struct uni_msg *msg;
667122219Sharti	int error;
668122219Sharti
669122219Sharti	if (!priv->enabled) {
670122219Sharti		NG_FREE_ITEM(item);
671122219Sharti		return (ENOTCONN);
672122219Sharti	}
673122219Sharti
674122219Sharti	NGI_GET_M(item, m);
675122219Sharti	NG_FREE_ITEM(item);
676122219Sharti
677122219Sharti	if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
678122219Sharti		m_freem(m);
679122219Sharti		return (error);
680122219Sharti	}
681122219Sharti	m_freem(m);
682122219Sharti
683122219Sharti	if (uni_msg_len(msg) < sizeof(arg)) {
684122219Sharti		uni_msg_destroy(msg);
685148915Sobrien		printf("%s: packet too short\n", __func__);
686122219Sharti		return (EINVAL);
687122219Sharti	}
688122219Sharti	bcopy(msg->b_rptr, &arg, sizeof(arg));
689122219Sharti	msg->b_rptr += sizeof(arg);
690122219Sharti
691122219Sharti	if (arg.sig > SAAL_UDATA_indication) {
692122219Sharti		uni_msg_destroy(msg);
693148915Sobrien		printf("%s: bogus signal\n", __func__);
694122219Sharti		return (EINVAL);
695122219Sharti	}
696122219Sharti
697122219Sharti	if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
698122219Sharti		dump_saal_signal(node, arg.sig, msg, 0);
699122219Sharti
700122219Sharti	uni_saal_input(priv->uni, arg.sig, msg);
701122219Sharti	uni_work(priv->uni);
702122219Sharti
703122219Sharti	return (0);
704122219Sharti}
705122219Sharti
706122219Sharti/*
707122219Sharti * Send signal to sscop.
708122219Sharti * Pack the message into an mbuf chain.
709122219Sharti */
710122219Shartistatic void
711122219Shartiuni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
712122219Sharti{
713122219Sharti	node_p node = (node_p)varg;
714122219Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
715122219Sharti	struct mbuf *m;
716122219Sharti	struct sscfu_arg arg;
717122219Sharti	int error;
718122219Sharti
719122219Sharti	if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
720122219Sharti		dump_saal_signal(node, sig, msg, 1);
721122219Sharti
722122219Sharti	if (priv->lower == NULL) {
723122219Sharti		if (msg != NULL)
724122219Sharti			uni_msg_destroy(msg);
725122219Sharti		return;
726122219Sharti	}
727122219Sharti
728122219Sharti	arg.sig = sig;
729122219Sharti
730122219Sharti	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
731122219Sharti	if (msg != NULL)
732122219Sharti		uni_msg_destroy(msg);
733122219Sharti	if (m == NULL)
734122219Sharti		return;
735122219Sharti
736122219Sharti	NG_SEND_DATA_ONLY(error, priv->lower, m);
737122219Sharti}
738122219Sharti
739122219Shartistatic void
740122219Shartiuni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
741122219Sharti{
742122219Sharti	va_list ap;
743122219Sharti
744122219Sharti	static char *facnames[] = {
745194825Srdivacky#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
746122219Sharti		UNI_DEBUG_FACILITIES
747122219Sharti#undef UNI_DEBUG_DEFINE
748122219Sharti	};
749122219Sharti
750122219Sharti	printf("%s: ", facnames[fac]);
751122219Sharti
752122219Sharti	va_start(ap, fmt);
753122219Sharti	vprintf(fmt, ap);
754122219Sharti	va_end(ap);
755122219Sharti
756122219Sharti	printf("\n");
757122219Sharti}
758122219Sharti
759122219Sharti
760122219Sharti/************************************************************/
761122219Sharti/*
762122219Sharti * Memory debugging
763122219Sharti */
764122219Shartistruct unimem_debug {
765122219Sharti	const char	*file;
766122219Sharti	u_int		lno;
767122219Sharti	LIST_ENTRY(unimem_debug) link;
768122219Sharti	char		data[0];
769122219Sharti};
770122219ShartiLIST_HEAD(unimem_debug_list, unimem_debug);
771122219Sharti
772122219Shartistatic struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
773201145Santoine    LIST_HEAD_INITIALIZER(nguni_freemem[0]),
774201145Santoine    LIST_HEAD_INITIALIZER(nguni_freemem[1]),
775201145Santoine    LIST_HEAD_INITIALIZER(nguni_freemem[2]),
776201145Santoine    LIST_HEAD_INITIALIZER(nguni_freemem[3]),
777201145Santoine    LIST_HEAD_INITIALIZER(nguni_freemem[4]),
778122219Sharti};
779122219Shartistatic struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
780201145Santoine    LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
781201145Santoine    LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
782201145Santoine    LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
783201145Santoine    LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
784201145Santoine    LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
785122219Sharti};
786122219Sharti
787122219Shartistatic struct mtx nguni_unilist_mtx;
788122219Sharti
789122219Shartistatic const char *unimem_names[UNIMEM_TYPES] = {
790122219Sharti	"instance",
791122219Sharti	"all",
792122219Sharti	"signal",
793122219Sharti	"call",
794122219Sharti	"party"
795122219Sharti};
796122219Sharti
797122219Shartistatic void
798122219Shartiuni_init(void)
799122219Sharti{
800123541Struckman	mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
801123541Struckman	    MTX_DEF);
802122219Sharti}
803122219Sharti
804122219Shartistatic void
805122219Shartiuni_fini(void)
806122219Sharti{
807122219Sharti	u_int type;
808122219Sharti	struct unimem_debug *h;
809122219Sharti
810122219Sharti	for (type = 0; type < UNIMEM_TYPES; type++) {
811122219Sharti		while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
812122219Sharti			LIST_REMOVE(h, link);
813122219Sharti			free(h, M_UNI);
814122219Sharti		}
815122219Sharti
816122219Sharti		while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
817122219Sharti			LIST_REMOVE(h, link);
818122219Sharti			printf("ng_uni: %s in use: %p (%s,%u)\n",
819122219Sharti			    unimem_names[type], (caddr_t)h->data,
820122219Sharti			    h->file, h->lno);
821122219Sharti			free(h, M_UNI);
822122219Sharti		}
823122219Sharti	}
824122219Sharti
825122219Sharti	mtx_destroy(&nguni_unilist_mtx);
826122219Sharti}
827122219Sharti
828122219Sharti/*
829122219Sharti * Allocate a chunk of memory from a given type.
830122219Sharti */
831122219Shartivoid *
832122219Sharting_uni_malloc(enum unimem type, const char *file, u_int lno)
833122219Sharti{
834122219Sharti	struct unimem_debug *d;
835122219Sharti	size_t full;
836122219Sharti
837122219Sharti	/*
838122219Sharti	 * Try to allocate
839122219Sharti	 */
840122219Sharti	mtx_lock(&nguni_unilist_mtx);
841122219Sharti	if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
842122219Sharti		LIST_REMOVE(d, link);
843122219Sharti	mtx_unlock(&nguni_unilist_mtx);
844122219Sharti
845122219Sharti	if (d == NULL) {
846122219Sharti		/*
847122219Sharti		 * allocate
848122219Sharti		 */
849122219Sharti		full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
850122219Sharti		if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
851122219Sharti			return (NULL);
852122219Sharti	} else {
853122219Sharti		bzero(d->data, unimem_sizes[type]);
854122219Sharti	}
855122219Sharti	d->file = file;
856122219Sharti	d->lno = lno;
857122219Sharti
858122219Sharti	mtx_lock(&nguni_unilist_mtx);
859122219Sharti	LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
860122219Sharti	mtx_unlock(&nguni_unilist_mtx);
861122219Sharti	return (d->data);
862122219Sharti}
863122219Sharti
864122219Shartivoid
865122219Sharting_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
866122219Sharti{
867122219Sharti	struct unimem_debug *d, *h;
868122219Sharti
869122219Sharti	d = (struct unimem_debug *)
870122219Sharti	    ((char *)ptr - offsetof(struct unimem_debug, data));
871122219Sharti
872122219Sharti	mtx_lock(&nguni_unilist_mtx);
873122219Sharti
874122219Sharti	LIST_FOREACH(h, &nguni_usedmem[type], link)
875122219Sharti		if (d == h)
876122219Sharti			break;
877122219Sharti
878122219Sharti	if (h != NULL) {
879122219Sharti		LIST_REMOVE(d, link);
880122219Sharti		LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
881122219Sharti	} else {
882122219Sharti		/*
883122219Sharti		 * Not on used list - try free list.
884122219Sharti		 */
885122219Sharti		LIST_FOREACH(h, &nguni_freemem[type], link)
886122219Sharti			if (d == h)
887122219Sharti				break;
888122219Sharti		if (h == NULL)
889122219Sharti			printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
890122219Sharti			    file, lno, ptr, unimem_names[type]);
891122219Sharti		else
892122219Sharti			printf("ng_uni: %s,%u: %p(%s) was already destroyed "
893122219Sharti			    "in %s,%u\n",
894122219Sharti			    file, lno, ptr, unimem_names[type],
895122219Sharti			    h->file, h->lno);
896122219Sharti	}
897122219Sharti	mtx_unlock(&nguni_unilist_mtx);
898122219Sharti}
899122219Sharti/************************************************************/
900122219Sharti/*
901122219Sharti * INITIALISATION
902122219Sharti */
903122219Sharti
904122219Sharti/*
905122219Sharti * Loading and unloading of node type
906122219Sharti */
907122219Shartistatic int
908122219Sharting_uni_mod_event(module_t mod, int event, void *data)
909122219Sharti{
910122219Sharti	int error = 0;
911122219Sharti
912122219Sharti	switch(event) {
913122219Sharti
914122219Sharti	  case MOD_LOAD:
915122219Sharti		uni_init();
916122219Sharti		break;
917122219Sharti
918122219Sharti	  case MOD_UNLOAD:
919122219Sharti		uni_fini();
920122219Sharti		break;
921122219Sharti
922122219Sharti	  default:
923122219Sharti		error = EOPNOTSUPP;
924122219Sharti		break;
925122219Sharti	}
926122219Sharti	return (error);
927122219Sharti}
928