xref: /f-stack/freebsd/netgraph/atm/uni/ng_uni.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001-2003
5  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6  * 	All rights reserved.
7  *
8  * Author: Hartmut Brandt <[email protected]>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * Netgraph module for ATM-Forum UNI 4.0 signalling
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/errno.h>
43 #include <sys/syslog.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/callout.h>
47 #include <sys/sbuf.h>
48 #include <machine/stdarg.h>
49 
50 #include <netgraph/ng_message.h>
51 #include <netgraph/netgraph.h>
52 #include <netgraph/ng_parse.h>
53 #include <netnatm/unimsg.h>
54 #include <netnatm/msg/unistruct.h>
55 #include <netgraph/atm/ngatmbase.h>
56 #include <netnatm/saal/sscopdef.h>
57 #include <netnatm/saal/sscfudef.h>
58 #include <netgraph/atm/uni/ng_uni_cust.h>
59 #include <netnatm/sig/uni.h>
60 #include <netnatm/sig/unisig.h>
61 #include <netgraph/atm/ng_sscop.h>
62 #include <netgraph/atm/ng_sscfu.h>
63 #include <netgraph/atm/ng_uni.h>
64 
65 static MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
66 static MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data");
67 
68 MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
69 
70 /*
71  * Private node data
72  */
73 struct priv {
74 	hook_p	upper;
75 	hook_p	lower;
76 	struct uni *uni;
77 	int	enabled;
78 };
79 
80 /* UNI CONFIG MASK */
81 static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] =
82 	NGM_UNI_CONFIG_MASK_INFO;
83 static const struct ng_parse_type ng_uni_config_mask_type = {
84 	&ng_parse_struct_type,
85 	ng_uni_config_mask_type_info
86 };
87 
88 /* UNI_CONFIG */
89 static const struct ng_parse_struct_field ng_uni_config_type_info[] =
90 	NGM_UNI_CONFIG_INFO;
91 static const struct ng_parse_type ng_uni_config_type = {
92 	&ng_parse_struct_type,
93 	ng_uni_config_type_info
94 };
95 
96 /* SET CONFIG */
97 static const struct ng_parse_struct_field ng_uni_set_config_type_info[] =
98 	NGM_UNI_SET_CONFIG_INFO;
99 static const struct ng_parse_type ng_uni_set_config_type = {
100 	&ng_parse_struct_type,
101 	ng_uni_set_config_type_info
102 };
103 
104 /*
105  * Parse DEBUG
106  */
107 static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info =
108     NGM_UNI_DEBUGLEVEL_INFO;
109 static const struct ng_parse_type ng_uni_debuglevel_type = {
110 	&ng_parse_fixedarray_type,
111 	&ng_uni_debuglevel_type_info
112 };
113 static const struct ng_parse_struct_field ng_uni_debug_type_info[] =
114     NGM_UNI_DEBUG_INFO;
115 static const struct ng_parse_type ng_uni_debug_type = {
116 	&ng_parse_struct_type,
117 	ng_uni_debug_type_info
118 };
119 
120 /*
121  * Command list
122  */
123 static const struct ng_cmdlist ng_uni_cmdlist[] = {
124 	{
125 	  NGM_UNI_COOKIE,
126 	  NGM_UNI_GETDEBUG,
127 	  "getdebug",
128 	  NULL,
129 	  &ng_uni_debug_type
130 	},
131 	{
132 	  NGM_UNI_COOKIE,
133 	  NGM_UNI_SETDEBUG,
134 	  "setdebug",
135 	  &ng_uni_debug_type,
136 	  NULL
137 	},
138 	{
139 	  NGM_UNI_COOKIE,
140 	  NGM_UNI_GET_CONFIG,
141 	  "get_config",
142 	  NULL,
143 	  &ng_uni_config_type
144 	},
145 	{
146 	  NGM_UNI_COOKIE,
147 	  NGM_UNI_SET_CONFIG,
148 	  "set_config",
149 	  &ng_uni_set_config_type,
150 	  &ng_uni_config_mask_type,
151 	},
152 	{
153 	  NGM_UNI_COOKIE,
154 	  NGM_UNI_ENABLE,
155 	  "enable",
156 	  NULL,
157 	  NULL,
158 	},
159 	{
160 	  NGM_UNI_COOKIE,
161 	  NGM_UNI_DISABLE,
162 	  "disable",
163 	  NULL,
164 	  NULL,
165 	},
166 	{
167 	  NGM_UNI_COOKIE,
168 	  NGM_UNI_GETSTATE,
169 	  "getstate",
170 	  NULL,
171 	  &ng_parse_uint32_type
172 	},
173 	{ 0 }
174 };
175 
176 /*
177  * Netgraph module data
178  */
179 static ng_constructor_t ng_uni_constructor;
180 static ng_shutdown_t	ng_uni_shutdown;
181 static ng_rcvmsg_t	ng_uni_rcvmsg;
182 static ng_newhook_t	ng_uni_newhook;
183 static ng_disconnect_t	ng_uni_disconnect;
184 static ng_rcvdata_t	ng_uni_rcvlower;
185 static ng_rcvdata_t	ng_uni_rcvupper;
186 
187 static int ng_uni_mod_event(module_t, int, void *);
188 
189 static struct ng_type ng_uni_typestruct = {
190 	.version =	NG_ABI_VERSION,
191 	.name =		NG_UNI_NODE_TYPE,
192 	.mod_event =	ng_uni_mod_event,
193 	.constructor =	ng_uni_constructor,
194 	.rcvmsg =	ng_uni_rcvmsg,
195 	.shutdown =	ng_uni_shutdown,
196 	.newhook =	ng_uni_newhook,
197 	.rcvdata =	ng_uni_rcvlower,
198 	.disconnect =	ng_uni_disconnect,
199 	.cmdlist =	ng_uni_cmdlist,
200 };
201 NETGRAPH_INIT(uni, &ng_uni_typestruct);
202 
203 static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
204     struct uni_msg *);
205 static void uni_saal_output(struct uni *, void *, enum saal_sig,
206     struct uni_msg *);
207 static void uni_verbose(struct uni *, void *, u_int, const char *, ...)
208     __printflike(4, 5);
209 static void uni_do_status(struct uni *, void *, void *, const char *, ...)
210     __printflike(4, 5);
211 
212 static const struct uni_funcs uni_funcs = {
213 	uni_uni_output,
214 	uni_saal_output,
215 	uni_verbose,
216 	uni_do_status
217 };
218 
219 /************************************************************/
220 /*
221  * NODE MANAGEMENT
222  */
223 static int
ng_uni_constructor(node_p node)224 ng_uni_constructor(node_p node)
225 {
226 	struct priv *priv;
227 
228 	priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO);
229 
230 	if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
231 		free(priv, M_NG_UNI);
232 		return (ENOMEM);
233 	}
234 
235 	NG_NODE_SET_PRIVATE(node, priv);
236 	NG_NODE_FORCE_WRITER(node);
237 
238 	return (0);
239 }
240 
241 static int
ng_uni_shutdown(node_p node)242 ng_uni_shutdown(node_p node)
243 {
244 	struct priv *priv = NG_NODE_PRIVATE(node);
245 
246 	uni_destroy(priv->uni);
247 
248 	free(priv, M_NG_UNI);
249 	NG_NODE_SET_PRIVATE(node, NULL);
250 
251 	NG_NODE_UNREF(node);
252 
253 	return (0);
254 }
255 
256 /************************************************************/
257 /*
258  * CONTROL MESSAGES
259  */
260 static void
uni_do_status(struct uni * uni,void * uarg,void * sbuf,const char * fmt,...)261 uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
262 {
263 	va_list ap;
264 
265 	va_start(ap, fmt);
266 	sbuf_printf(sbuf, fmt, ap);
267 	va_end(ap);
268 }
269 
270 static int
text_status(node_p node,struct priv * priv,char * buf,u_int len)271 text_status(node_p node, struct priv *priv, char *buf, u_int len)
272 {
273 	struct sbuf sbuf;
274 	u_int f;
275 
276 	sbuf_new(&sbuf, buf, len, 0);
277 
278 	if (priv->lower != NULL)
279 		sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
280 		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
281 		    NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
282 	else
283 		sbuf_printf(&sbuf, "lower hook: <not connected>\n");
284 
285 	if (priv->upper != NULL)
286 		sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
287 		    NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
288 		    NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
289 	else
290 		sbuf_printf(&sbuf, "upper hook: <not connected>\n");
291 
292 	sbuf_printf(&sbuf, "debugging:");
293 	for (f = 0; f < UNI_MAXFACILITY; f++)
294 		if (uni_get_debug(priv->uni, f) != 0)
295 			sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
296 			    uni_get_debug(priv->uni, f));
297 	sbuf_printf(&sbuf, "\n");
298 
299 	if (priv->uni)
300 		uni_status(priv->uni, &sbuf);
301 
302 	sbuf_finish(&sbuf);
303 	return (sbuf_len(&sbuf));
304 }
305 
306 static int
ng_uni_rcvmsg(node_p node,item_p item,hook_p lasthook)307 ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
308 {
309 	struct priv *priv = NG_NODE_PRIVATE(node);
310 	struct ng_mesg *resp = NULL;
311 	struct ng_mesg *msg;
312 	int error = 0;
313 	u_int i;
314 
315 	NGI_GET_MSG(item, msg);
316 
317 	switch (msg->header.typecookie) {
318 	  case NGM_GENERIC_COOKIE:
319 		switch (msg->header.cmd) {
320 		  case NGM_TEXT_STATUS:
321 			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
322 			if (resp == NULL) {
323 				error = ENOMEM;
324 				break;
325 			}
326 
327 			resp->header.arglen = text_status(node, priv,
328 			    (char *)resp->data, resp->header.arglen) + 1;
329 			break;
330 
331 		  default:
332 			error = EINVAL;
333 			break;
334 		}
335 		break;
336 
337 	  case NGM_UNI_COOKIE:
338 		switch (msg->header.cmd) {
339 		  case NGM_UNI_SETDEBUG:
340 		    {
341 			struct ngm_uni_debug *arg;
342 
343 			if (msg->header.arglen > sizeof(*arg)) {
344 				error = EINVAL;
345 				break;
346 			}
347 			arg = (struct ngm_uni_debug *)msg->data;
348 			for (i = 0; i < UNI_MAXFACILITY; i++)
349 				uni_set_debug(priv->uni, i, arg->level[i]);
350 			break;
351 		    }
352 
353 		  case NGM_UNI_GETDEBUG:
354 		    {
355 			struct ngm_uni_debug *arg;
356 
357 			NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
358 			if(resp == NULL) {
359 				error = ENOMEM;
360 				break;
361 			}
362 			arg = (struct ngm_uni_debug *)resp->data;
363 			for (i = 0; i < UNI_MAXFACILITY; i++)
364 				arg->level[i] = uni_get_debug(priv->uni, i);
365 			break;
366 		    }
367 
368 		  case NGM_UNI_GET_CONFIG:
369 		    {
370 			struct uni_config *config;
371 
372 			if (msg->header.arglen != 0) {
373 				error = EINVAL;
374 				break;
375 			}
376 			NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
377 			if (resp == NULL) {
378 				error = ENOMEM;
379 				break;
380 			}
381 			config = (struct uni_config *)resp->data;
382 			uni_get_config(priv->uni, config);
383 
384 			break;
385 		    }
386 
387 		  case NGM_UNI_SET_CONFIG:
388 		    {
389 			struct ngm_uni_set_config *arg;
390 			struct ngm_uni_config_mask *mask;
391 
392 			if (msg->header.arglen != sizeof(*arg)) {
393 				error = EINVAL;
394 				break;
395 			}
396 			arg = (struct ngm_uni_set_config *)msg->data;
397 
398 			NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
399 			if (resp == NULL) {
400 				error = ENOMEM;
401 				break;
402 			}
403 			mask = (struct ngm_uni_config_mask *)resp->data;
404 
405 			*mask = arg->mask;
406 
407 			uni_set_config(priv->uni, &arg->config,
408 			    &mask->mask, &mask->popt_mask, &mask->option_mask);
409 
410 			break;
411 		    }
412 
413 		  case NGM_UNI_ENABLE:
414 			if (msg->header.arglen != 0) {
415 				error = EINVAL;
416 				break;
417 			}
418 			if (priv->enabled) {
419 				error = EISCONN;
420 				break;
421 			}
422 			priv->enabled = 1;
423 			break;
424 
425 		  case NGM_UNI_DISABLE:
426 			if (msg->header.arglen != 0) {
427 				error = EINVAL;
428 				break;
429 			}
430 			if (!priv->enabled) {
431 				error = ENOTCONN;
432 				break;
433 			}
434 			priv->enabled = 0;
435 			uni_reset(priv->uni);
436 			break;
437 
438 		  case NGM_UNI_GETSTATE:
439 			if (msg->header.arglen != 0) {
440 				error = EINVAL;
441 				break;
442 			}
443 			NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
444 			if(resp == NULL) {
445 				error = ENOMEM;
446 				break;
447 			}
448 			*(u_int32_t *)resp->data =
449 			    priv->enabled ? (uni_getcustate(priv->uni) + 1)
450 			                  : 0;
451 			break;
452 
453 		  default:
454 			error = EINVAL;
455 			break;
456 		}
457 		break;
458 
459 	  default:
460 		error = EINVAL;
461 		break;
462 	}
463 
464 	NG_RESPOND_MSG(error, node, item, resp);
465 	NG_FREE_MSG(msg);
466 	return (error);
467 }
468 
469 /************************************************************/
470 /*
471  * HOOK MANAGEMENT
472  */
473 static int
ng_uni_newhook(node_p node,hook_p hook,const char * name)474 ng_uni_newhook(node_p node, hook_p hook, const char *name)
475 {
476 	struct priv *priv = NG_NODE_PRIVATE(node);
477 
478 	if (strcmp(name, "lower") == 0) {
479 		priv->lower = hook;
480 	} else if(strcmp(name, "upper") == 0) {
481 		priv->upper = hook;
482 		NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
483 	} else
484 		return EINVAL;
485 
486 	return 0;
487 }
488 
489 static int
ng_uni_disconnect(hook_p hook)490 ng_uni_disconnect(hook_p hook)
491 {
492 	node_p node = NG_HOOK_NODE(hook);
493 	struct priv *priv = NG_NODE_PRIVATE(node);
494 
495 	if(hook == priv->lower)
496 		priv->lower = NULL;
497 	else if(hook == priv->upper)
498 		priv->upper = NULL;
499 	else
500 		printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
501 
502 	if (NG_NODE_NUMHOOKS(node) == 0) {
503 		if (NG_NODE_IS_VALID(node))
504 			ng_rmnode_self(node);
505 	}
506 
507 	return (0);
508 }
509 
510 /************************************************************/
511 /*
512  * DATA
513  */
514 /*
515  * Receive signal from USER.
516  *
517  * Repackage the data into one large buffer.
518  */
519 static int
ng_uni_rcvupper(hook_p hook,item_p item)520 ng_uni_rcvupper(hook_p hook, item_p item)
521 {
522 	node_p node = NG_HOOK_NODE(hook);
523 	struct priv *priv = NG_NODE_PRIVATE(node);
524 	struct mbuf *m;
525 	struct uni_arg arg;
526 	struct uni_msg *msg;
527 	int error;
528 
529 	if (!priv->enabled) {
530 		NG_FREE_ITEM(item);
531 		return (ENOTCONN);
532 	}
533 
534 	NGI_GET_M(item, m);
535 	NG_FREE_ITEM(item);
536 
537 	if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
538 		m_freem(m);
539 		return (error);
540 	}
541 	m_freem(m);
542 
543 	if (uni_msg_len(msg) < sizeof(arg)) {
544 		printf("%s: packet too short\n", __func__);
545 		uni_msg_destroy(msg);
546 		return (EINVAL);
547 	}
548 
549 	bcopy(msg->b_rptr, &arg, sizeof(arg));
550 	msg->b_rptr += sizeof(arg);
551 
552 	if (arg.sig >= UNIAPI_MAXSIG) {
553 		printf("%s: bogus signal\n", __func__);
554 		uni_msg_destroy(msg);
555 		return (EINVAL);
556 	}
557 	uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
558 	uni_work(priv->uni);
559 
560 	return (0);
561 }
562 
563 /*
564  * Upper layer signal from UNI
565  */
566 static void
uni_uni_output(struct uni * uni,void * varg,enum uni_sig sig,u_int32_t cookie,struct uni_msg * msg)567 uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
568     struct uni_msg *msg)
569 {
570 	node_p node = (node_p)varg;
571 	struct priv *priv = NG_NODE_PRIVATE(node);
572 	struct mbuf *m;
573 	struct uni_arg arg;
574 	int error;
575 
576 	if (priv->upper == NULL) {
577 		if (msg != NULL)
578 			uni_msg_destroy(msg);
579 		return;
580 	}
581 	arg.sig = sig;
582 	arg.cookie = cookie;
583 
584 	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
585 	if (msg != NULL)
586 		uni_msg_destroy(msg);
587 	if (m == NULL)
588 		return;
589 
590 	NG_SEND_DATA_ONLY(error, priv->upper, m);
591 }
592 
593 static void
dump_uni_msg(struct uni_msg * msg)594 dump_uni_msg(struct uni_msg *msg)
595 {
596 	u_int pos;
597 
598 	for (pos = 0; pos < uni_msg_len(msg); pos++) {
599 		if (pos % 16 == 0)
600 			printf("%06o ", pos);
601 		if (pos % 16 == 8)
602 			printf("  ");
603 		printf(" %02x", msg->b_rptr[pos]);
604 		if (pos % 16 == 15)
605 			printf("\n");
606 	}
607 	if (pos % 16 != 0)
608 		printf("\n");
609 }
610 
611 /*
612  * Dump a SAAL signal in either direction
613  */
614 static void
dump_saal_signal(node_p node,enum saal_sig sig,struct uni_msg * msg,int to)615 dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
616 {
617 	struct priv *priv = NG_NODE_PRIVATE(node);
618 
619 	printf("signal %s SAAL: ", to ? "to" : "from");
620 
621 	switch (sig) {
622 #define D(S) case S: printf("%s", #S); break
623 
624 	D(SAAL_ESTABLISH_request);
625 	D(SAAL_ESTABLISH_indication);
626 	D(SAAL_ESTABLISH_confirm);
627 	D(SAAL_RELEASE_request);
628 	D(SAAL_RELEASE_confirm);
629 	D(SAAL_RELEASE_indication);
630 	D(SAAL_DATA_request);
631 	D(SAAL_DATA_indication);
632 	D(SAAL_UDATA_request);
633 	D(SAAL_UDATA_indication);
634 
635 #undef D
636 	  default:
637 		printf("sig=%d", sig); break;
638 	}
639 	if (msg != NULL) {
640 		printf(" data=%zu\n", uni_msg_len(msg));
641 		if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
642 			dump_uni_msg(msg);
643 	} else
644 		printf("\n");
645 }
646 
647 /*
648  * Receive signal from SSCOP.
649  *
650  * If this is a data signal, repackage the data into one large buffer.
651  * UNI shouldn't be the bottleneck in a system and this greatly simplifies
652  * parsing in UNI.
653  */
654 static int
ng_uni_rcvlower(hook_p hook __unused,item_p item)655 ng_uni_rcvlower(hook_p hook __unused, item_p item)
656 {
657 	node_p node = NG_HOOK_NODE(hook);
658 	struct priv *priv = NG_NODE_PRIVATE(node);
659 	struct mbuf *m;
660 	struct sscfu_arg arg;
661 	struct uni_msg *msg;
662 	int error;
663 
664 	if (!priv->enabled) {
665 		NG_FREE_ITEM(item);
666 		return (ENOTCONN);
667 	}
668 
669 	NGI_GET_M(item, m);
670 	NG_FREE_ITEM(item);
671 
672 	if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
673 		m_freem(m);
674 		return (error);
675 	}
676 	m_freem(m);
677 
678 	if (uni_msg_len(msg) < sizeof(arg)) {
679 		uni_msg_destroy(msg);
680 		printf("%s: packet too short\n", __func__);
681 		return (EINVAL);
682 	}
683 	bcopy(msg->b_rptr, &arg, sizeof(arg));
684 	msg->b_rptr += sizeof(arg);
685 
686 	if (arg.sig > SAAL_UDATA_indication) {
687 		uni_msg_destroy(msg);
688 		printf("%s: bogus signal\n", __func__);
689 		return (EINVAL);
690 	}
691 
692 	if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
693 		dump_saal_signal(node, arg.sig, msg, 0);
694 
695 	uni_saal_input(priv->uni, arg.sig, msg);
696 	uni_work(priv->uni);
697 
698 	return (0);
699 }
700 
701 /*
702  * Send signal to sscop.
703  * Pack the message into an mbuf chain.
704  */
705 static void
uni_saal_output(struct uni * uni,void * varg,enum saal_sig sig,struct uni_msg * msg)706 uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
707 {
708 	node_p node = (node_p)varg;
709 	struct priv *priv = NG_NODE_PRIVATE(node);
710 	struct mbuf *m;
711 	struct sscfu_arg arg;
712 	int error;
713 
714 	if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
715 		dump_saal_signal(node, sig, msg, 1);
716 
717 	if (priv->lower == NULL) {
718 		if (msg != NULL)
719 			uni_msg_destroy(msg);
720 		return;
721 	}
722 
723 	arg.sig = sig;
724 
725 	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
726 	if (msg != NULL)
727 		uni_msg_destroy(msg);
728 	if (m == NULL)
729 		return;
730 
731 	NG_SEND_DATA_ONLY(error, priv->lower, m);
732 }
733 
734 static void
uni_verbose(struct uni * uni,void * varg,u_int fac,const char * fmt,...)735 uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
736 {
737 	va_list ap;
738 
739 	static char *facnames[] = {
740 #define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
741 		UNI_DEBUG_FACILITIES
742 #undef UNI_DEBUG_DEFINE
743 	};
744 
745 	printf("%s: ", facnames[fac]);
746 
747 	va_start(ap, fmt);
748 	vprintf(fmt, ap);
749 	va_end(ap);
750 
751 	printf("\n");
752 }
753 
754 /************************************************************/
755 /*
756  * Memory debugging
757  */
758 struct unimem_debug {
759 	const char	*file;
760 	u_int		lno;
761 	LIST_ENTRY(unimem_debug) link;
762 	char		data[0];
763 };
764 LIST_HEAD(unimem_debug_list, unimem_debug);
765 
766 static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
767     LIST_HEAD_INITIALIZER(nguni_freemem[0]),
768     LIST_HEAD_INITIALIZER(nguni_freemem[1]),
769     LIST_HEAD_INITIALIZER(nguni_freemem[2]),
770     LIST_HEAD_INITIALIZER(nguni_freemem[3]),
771     LIST_HEAD_INITIALIZER(nguni_freemem[4]),
772 };
773 static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
774     LIST_HEAD_INITIALIZER(nguni_usedmem[0]),
775     LIST_HEAD_INITIALIZER(nguni_usedmem[1]),
776     LIST_HEAD_INITIALIZER(nguni_usedmem[2]),
777     LIST_HEAD_INITIALIZER(nguni_usedmem[3]),
778     LIST_HEAD_INITIALIZER(nguni_usedmem[4]),
779 };
780 
781 static struct mtx nguni_unilist_mtx;
782 
783 static const char *unimem_names[UNIMEM_TYPES] = {
784 	"instance",
785 	"all",
786 	"signal",
787 	"call",
788 	"party"
789 };
790 
791 static void
uni_init(void)792 uni_init(void)
793 {
794 	mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
795 	    MTX_DEF);
796 }
797 
798 static void
uni_fini(void)799 uni_fini(void)
800 {
801 	u_int type;
802 	struct unimem_debug *h;
803 
804 	for (type = 0; type < UNIMEM_TYPES; type++) {
805 		while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
806 			LIST_REMOVE(h, link);
807 			free(h, M_UNI);
808 		}
809 
810 		while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
811 			LIST_REMOVE(h, link);
812 			printf("ng_uni: %s in use: %p (%s,%u)\n",
813 			    unimem_names[type], (caddr_t)h->data,
814 			    h->file, h->lno);
815 			free(h, M_UNI);
816 		}
817 	}
818 
819 	mtx_destroy(&nguni_unilist_mtx);
820 }
821 
822 /*
823  * Allocate a chunk of memory from a given type.
824  */
825 void *
ng_uni_malloc(enum unimem type,const char * file,u_int lno)826 ng_uni_malloc(enum unimem type, const char *file, u_int lno)
827 {
828 	struct unimem_debug *d;
829 	size_t full;
830 
831 	/*
832 	 * Try to allocate
833 	 */
834 	mtx_lock(&nguni_unilist_mtx);
835 	if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
836 		LIST_REMOVE(d, link);
837 	mtx_unlock(&nguni_unilist_mtx);
838 
839 	if (d == NULL) {
840 		/*
841 		 * allocate
842 		 */
843 		full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
844 		if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
845 			return (NULL);
846 	} else {
847 		bzero(d->data, unimem_sizes[type]);
848 	}
849 	d->file = file;
850 	d->lno = lno;
851 
852 	mtx_lock(&nguni_unilist_mtx);
853 	LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
854 	mtx_unlock(&nguni_unilist_mtx);
855 	return (d->data);
856 }
857 
858 void
ng_uni_free(enum unimem type,void * ptr,const char * file,u_int lno)859 ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
860 {
861 	struct unimem_debug *d, *h;
862 
863 	d = (struct unimem_debug *)
864 	    ((char *)ptr - offsetof(struct unimem_debug, data));
865 
866 	mtx_lock(&nguni_unilist_mtx);
867 
868 	LIST_FOREACH(h, &nguni_usedmem[type], link)
869 		if (d == h)
870 			break;
871 
872 	if (h != NULL) {
873 		LIST_REMOVE(d, link);
874 		LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
875 	} else {
876 		/*
877 		 * Not on used list - try free list.
878 		 */
879 		LIST_FOREACH(h, &nguni_freemem[type], link)
880 			if (d == h)
881 				break;
882 		if (h == NULL)
883 			printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
884 			    file, lno, ptr, unimem_names[type]);
885 		else
886 			printf("ng_uni: %s,%u: %p(%s) was already destroyed "
887 			    "in %s,%u\n",
888 			    file, lno, ptr, unimem_names[type],
889 			    h->file, h->lno);
890 	}
891 	mtx_unlock(&nguni_unilist_mtx);
892 }
893 /************************************************************/
894 /*
895  * INITIALISATION
896  */
897 
898 /*
899  * Loading and unloading of node type
900  */
901 static int
ng_uni_mod_event(module_t mod,int event,void * data)902 ng_uni_mod_event(module_t mod, int event, void *data)
903 {
904 	int error = 0;
905 
906 	switch(event) {
907 	  case MOD_LOAD:
908 		uni_init();
909 		break;
910 
911 	  case MOD_UNLOAD:
912 		uni_fini();
913 		break;
914 
915 	  default:
916 		error = EOPNOTSUPP;
917 		break;
918 	}
919 	return (error);
920 }
921