xref: /freebsd-12.1/sys/netgraph/atm/ccatm/ng_ccatm.c (revision 155d72c4)
1 /*-
2  * Copyright (c) 2001-2002
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *	All rights reserved.
5  * Copyright (c) 2003-2004
6  *	Hartmut Brandt
7  *	All rights reserved.
8  *
9  * Author: Harti Brandt <[email protected]>
10  *
11  * Redistribution of this software and documentation and use in source and
12  * binary forms, with or without modification, are permitted provided that
13  * the following conditions are met:
14  *
15  * 1. Redistributions of source code or documentation must retain the above
16  *    copyright notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
22  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25  * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $FreeBSD$
34  *
35  * ATM call control and API
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/errno.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/sbuf.h>
50 #include <machine/stdarg.h>
51 
52 #include <netgraph/ng_message.h>
53 #include <netgraph/netgraph.h>
54 #include <netgraph/ng_parse.h>
55 #include <netnatm/unimsg.h>
56 #include <netnatm/msg/unistruct.h>
57 #include <netnatm/api/unisap.h>
58 #include <netnatm/sig/unidef.h>
59 #include <netgraph/atm/ngatmbase.h>
60 #include <netgraph/atm/ng_uni.h>
61 #include <netnatm/api/atmapi.h>
62 #include <netgraph/atm/ng_ccatm.h>
63 #include <netnatm/api/ccatm.h>
64 
65 MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1);
66 
67 MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node");
68 
69 /*
70  * Command structure parsing
71  */
72 
73 /* ESI */
74 static const struct ng_parse_fixedarray_info ng_ccatm_esi_type_info =
75     NGM_CCATM_ESI_INFO;
76 static const struct ng_parse_type ng_ccatm_esi_type = {
77 	&ng_parse_fixedarray_type,
78 	&ng_ccatm_esi_type_info
79 };
80 
81 /* PORT PARAMETERS */
82 static const struct ng_parse_struct_field ng_ccatm_atm_port_type_info[] =
83     NGM_CCATM_ATM_PORT_INFO;
84 static const struct ng_parse_type ng_ccatm_atm_port_type = {
85 	&ng_parse_struct_type,
86 	ng_ccatm_atm_port_type_info
87 };
88 
89 /* PORT structure */
90 static const struct ng_parse_struct_field ng_ccatm_port_type_info[] =
91     NGM_CCATM_PORT_INFO;
92 static const struct ng_parse_type ng_ccatm_port_type = {
93 	&ng_parse_struct_type,
94 	ng_ccatm_port_type_info
95 };
96 
97 /* the ADDRESS array itself */
98 static const struct ng_parse_fixedarray_info ng_ccatm_addr_array_type_info =
99     NGM_CCATM_ADDR_ARRAY_INFO;
100 static const struct ng_parse_type ng_ccatm_addr_array_type = {
101 	&ng_parse_fixedarray_type,
102 	&ng_ccatm_addr_array_type_info
103 };
104 
105 /* one ADDRESS */
106 static const struct ng_parse_struct_field ng_ccatm_uni_addr_type_info[] =
107     NGM_CCATM_UNI_ADDR_INFO;
108 static const struct ng_parse_type ng_ccatm_uni_addr_type = {
109 	&ng_parse_struct_type,
110 	ng_ccatm_uni_addr_type_info
111 };
112 
113 /* ADDRESS request */
114 static const struct ng_parse_struct_field ng_ccatm_addr_req_type_info[] =
115     NGM_CCATM_ADDR_REQ_INFO;
116 static const struct ng_parse_type ng_ccatm_addr_req_type = {
117 	&ng_parse_struct_type,
118 	ng_ccatm_addr_req_type_info
119 };
120 
121 /* ADDRESS var-array */
122 static int
ng_ccatm_addr_req_array_getlen(const struct ng_parse_type * type,const u_char * start,const u_char * buf)123 ng_ccatm_addr_req_array_getlen(const struct ng_parse_type *type,
124     const u_char *start, const u_char *buf)
125 {
126 	const struct ngm_ccatm_get_addresses *p;
127 
128 	p = (const struct ngm_ccatm_get_addresses *)
129 	    (buf - offsetof(struct ngm_ccatm_get_addresses, addr));
130 	return (p->count);
131 }
132 static const struct ng_parse_array_info ng_ccatm_addr_req_array_type_info =
133     NGM_CCATM_ADDR_REQ_ARRAY_INFO;
134 static const struct ng_parse_type ng_ccatm_addr_req_array_type = {
135 	&ng_parse_array_type,
136 	&ng_ccatm_addr_req_array_type_info
137 };
138 
139 /* Outer get_ADDRESSes structure */
140 static const struct ng_parse_struct_field ng_ccatm_get_addresses_type_info[] =
141     NGM_CCATM_GET_ADDRESSES_INFO;
142 static const struct ng_parse_type ng_ccatm_get_addresses_type = {
143 	&ng_parse_struct_type,
144 	ng_ccatm_get_addresses_type_info
145 };
146 
147 /* Port array */
148 static int
ng_ccatm_port_array_getlen(const struct ng_parse_type * type,const u_char * start,const u_char * buf)149 ng_ccatm_port_array_getlen(const struct ng_parse_type *type,
150     const u_char *start, const u_char *buf)
151 {
152 	const struct ngm_ccatm_portlist *p;
153 
154 	p = (const struct ngm_ccatm_portlist *)
155 	    (buf - offsetof(struct ngm_ccatm_portlist, ports));
156 	return (p->nports);
157 }
158 static const struct ng_parse_array_info ng_ccatm_port_array_type_info =
159     NGM_CCATM_PORT_ARRAY_INFO;
160 static const struct ng_parse_type ng_ccatm_port_array_type = {
161 	&ng_parse_array_type,
162 	&ng_ccatm_port_array_type_info
163 };
164 
165 /* Portlist structure */
166 static const struct ng_parse_struct_field ng_ccatm_portlist_type_info[] =
167     NGM_CCATM_PORTLIST_INFO;
168 static const struct ng_parse_type ng_ccatm_portlist_type = {
169 	&ng_parse_struct_type,
170 	ng_ccatm_portlist_type_info
171 };
172 
173 /*
174  * Command list
175  */
176 static const struct ng_cmdlist ng_ccatm_cmdlist[] = {
177 	{
178 	  NGM_CCATM_COOKIE,
179 	  NGM_CCATM_DUMP,
180 	  "dump",
181 	  NULL,
182 	  NULL
183 	},
184 	{
185 	  NGM_CCATM_COOKIE,
186 	  NGM_CCATM_STOP,
187 	  "stop",
188 	  &ng_ccatm_port_type,
189 	  NULL
190 	},
191 	{
192 	  NGM_CCATM_COOKIE,
193 	  NGM_CCATM_START,
194 	  "start",
195 	  &ng_ccatm_port_type,
196 	  NULL
197 	},
198 	{
199 	  NGM_CCATM_COOKIE,
200 	  NGM_CCATM_GETSTATE,
201 	  "getstate",
202 	  &ng_ccatm_port_type,
203 	  &ng_parse_uint32_type
204 	},
205 	{
206 	  NGM_CCATM_COOKIE,
207 	  NGM_CCATM_GET_ADDRESSES,
208 	  "get_addresses",
209 	  &ng_ccatm_port_type,
210 	  &ng_ccatm_get_addresses_type
211 	},
212 	{
213 	  NGM_CCATM_COOKIE,
214 	  NGM_CCATM_CLEAR,
215 	  "clear",
216 	  &ng_ccatm_port_type,
217 	  NULL
218 	},
219 	{
220 	  NGM_CCATM_COOKIE,
221 	  NGM_CCATM_ADDRESS_REGISTERED,
222 	  "address_reg",
223 	  &ng_ccatm_addr_req_type,
224 	  NULL
225 	},
226 	{
227 	  NGM_CCATM_COOKIE,
228 	  NGM_CCATM_ADDRESS_UNREGISTERED,
229 	  "address_unreg",
230 	  &ng_ccatm_addr_req_type,
231 	  NULL
232 	},
233 	{
234 	  NGM_CCATM_COOKIE,
235 	  NGM_CCATM_SET_PORT_PARAM,
236 	  "set_port_param",
237 	  &ng_ccatm_atm_port_type,
238 	  NULL
239 	},
240 	{
241 	  NGM_CCATM_COOKIE,
242 	  NGM_CCATM_GET_PORT_PARAM,
243 	  "get_port_param",
244 	  &ng_ccatm_port_type,
245 	  &ng_ccatm_atm_port_type,
246 	},
247 	{
248 	  NGM_CCATM_COOKIE,
249 	  NGM_CCATM_GET_PORTLIST,
250 	  "get_portlist",
251 	  NULL,
252 	  &ng_ccatm_portlist_type,
253 	},
254 	{
255 	  NGM_CCATM_COOKIE,
256 	  NGM_CCATM_SETLOG,
257 	  "setlog",
258 	  &ng_parse_hint32_type,
259 	  &ng_parse_hint32_type,
260 	},
261 	{
262 	  NGM_CCATM_COOKIE,
263 	  NGM_CCATM_RESET,
264 	  "reset",
265 	  NULL,
266 	  NULL,
267 	},
268 	{ 0 }
269 };
270 
271 /*
272  * Module data
273  */
274 static ng_constructor_t		ng_ccatm_constructor;
275 static ng_rcvmsg_t		ng_ccatm_rcvmsg;
276 static ng_shutdown_t		ng_ccatm_shutdown;
277 static ng_newhook_t		ng_ccatm_newhook;
278 static ng_rcvdata_t		ng_ccatm_rcvdata;
279 static ng_disconnect_t		ng_ccatm_disconnect;
280 static int ng_ccatm_mod_event(module_t, int, void *);
281 
282 static struct ng_type ng_ccatm_typestruct = {
283 	.version =	NG_ABI_VERSION,
284 	.name =		NG_CCATM_NODE_TYPE,
285 	.mod_event =	ng_ccatm_mod_event,
286 	.constructor =	ng_ccatm_constructor,	/* Node constructor */
287 	.rcvmsg =	ng_ccatm_rcvmsg,	/* Control messages */
288 	.shutdown =	ng_ccatm_shutdown,	/* Node destructor */
289 	.newhook =	ng_ccatm_newhook,	/* Arrival of new hook */
290 	.rcvdata =	ng_ccatm_rcvdata,	/* receive data */
291 	.disconnect =	ng_ccatm_disconnect,	/* disconnect a hook */
292 	.cmdlist =	ng_ccatm_cmdlist,
293 };
294 NETGRAPH_INIT(ccatm, &ng_ccatm_typestruct);
295 
296 static ng_rcvdata_t	ng_ccatm_rcvuni;
297 static ng_rcvdata_t	ng_ccatm_rcvdump;
298 static ng_rcvdata_t	ng_ccatm_rcvmanage;
299 
300 /*
301  * Private node data.
302  */
303 struct ccnode {
304 	node_p	node;		/* the owning node */
305 	hook_p	dump;		/* dump hook */
306 	hook_p	manage;		/* hook to ILMI */
307 
308 	struct ccdata *data;
309 	struct mbuf *dump_first;
310 	struct mbuf *dump_last;	/* first and last mbuf when dumping */
311 
312 	u_int	hook_cnt;	/* count user and port hooks */
313 };
314 
315 /*
316  * Private UNI hook data
317  */
318 struct cchook {
319 	int		is_uni;	/* true if uni hook, user otherwise */
320 	struct ccnode	*node;	/* the owning node */
321 	hook_p		hook;
322 	void		*inst;	/* port or user */
323 };
324 
325 static void ng_ccatm_send_user(struct ccuser *, void *, u_int, void *, size_t);
326 static void ng_ccatm_respond_user(struct ccuser *, void *, int, u_int,
327     void *, size_t);
328 static void ng_ccatm_send_uni(struct ccconn *, void *, u_int, u_int,
329     struct uni_msg *);
330 static void ng_ccatm_send_uni_glob(struct ccport *, void *, u_int, u_int,
331     struct uni_msg *);
332 static void ng_ccatm_log(const char *, ...) __printflike(1, 2);
333 
334 static const struct cc_funcs cc_funcs = {
335 	.send_user =		ng_ccatm_send_user,
336 	.respond_user =		ng_ccatm_respond_user,
337 	.send_uni =		ng_ccatm_send_uni,
338 	.send_uni_glob =	ng_ccatm_send_uni_glob,
339 	.log =			ng_ccatm_log,
340 };
341 
342 /************************************************************
343  *
344  * Create a new node
345  */
346 static int
ng_ccatm_constructor(node_p node)347 ng_ccatm_constructor(node_p node)
348 {
349 	struct ccnode *priv;
350 
351 	priv = malloc(sizeof(*priv), M_NG_CCATM, M_WAITOK | M_ZERO);
352 
353 	priv->node = node;
354 	priv->data = cc_create(&cc_funcs);
355 	if (priv->data == NULL) {
356 		free(priv, M_NG_CCATM);
357 		return (ENOMEM);
358 	}
359 
360 	NG_NODE_SET_PRIVATE(node, priv);
361 
362 	return (0);
363 }
364 
365 /*
366  * Destroy a node. The user list is empty here, because all hooks are
367  * previously disconnected. The connection lists may not be empty, because
368  * connections may be waiting for responses from the stack. This also means,
369  * that no orphaned connections will be made by the port_destroy routine.
370  */
371 static int
ng_ccatm_shutdown(node_p node)372 ng_ccatm_shutdown(node_p node)
373 {
374 	struct ccnode *priv = NG_NODE_PRIVATE(node);
375 
376 	cc_destroy(priv->data);
377 
378 	free(priv, M_NG_CCATM);
379 	NG_NODE_SET_PRIVATE(node, NULL);
380 
381 	NG_NODE_UNREF(node);
382 
383 	return (0);
384 }
385 
386 /*
387  * Retrieve the registered addresses for one port or all ports.
388  * Returns an error code or 0 on success.
389  */
390 static int
ng_ccatm_get_addresses(node_p node,uint32_t portno,struct ng_mesg * msg,struct ng_mesg ** resp)391 ng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg,
392     struct ng_mesg **resp)
393 {
394 	struct ccnode *priv = NG_NODE_PRIVATE(node);
395 	struct uni_addr *addrs;
396 	u_int *ports;
397 	struct ngm_ccatm_get_addresses *list;
398 	u_int count, i;
399 	size_t len;
400 	int err;
401 
402 	err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count);
403 	if (err != 0)
404 		return (err);
405 
406 	len = sizeof(*list) + count * sizeof(list->addr[0]);
407 	NG_MKRESPONSE(*resp, msg, len, M_NOWAIT);
408 	if (*resp == NULL) {
409 		free(addrs, M_NG_CCATM);
410 		free(ports, M_NG_CCATM);
411 		return (ENOMEM);
412 	}
413 	list = (struct ngm_ccatm_get_addresses *)(*resp)->data;
414 
415 	list->count = count;
416 	for (i = 0; i < count; i++) {
417 		list->addr[i].port = ports[i];
418 		list->addr[i].addr = addrs[i];
419 	}
420 
421 	free(addrs, M_NG_CCATM);
422 	free(ports, M_NG_CCATM);
423 
424 	return (0);
425 }
426 
427 /*
428  * Dumper function. Pack the data into an mbuf chain.
429  */
430 static int
send_dump(struct ccdata * data,void * uarg,const char * buf)431 send_dump(struct ccdata *data, void *uarg, const char *buf)
432 {
433 	struct mbuf *m;
434 	struct ccnode *priv = uarg;
435 
436 	if (priv->dump == NULL) {
437 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
438 		if (m == NULL)
439 			return (ENOBUFS);
440 		priv->dump_first = priv->dump_last = m;
441 		m->m_pkthdr.len = 0;
442 	} else {
443 		m = m_getcl(M_NOWAIT, MT_DATA, 0);
444 		if (m == NULL) {
445 			m_freem(priv->dump_first);
446 			return (ENOBUFS);
447 		}
448 		priv->dump_last->m_next = m;
449 		priv->dump_last = m;
450 	}
451 
452 	strcpy(m->m_data, buf);
453 	priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf));
454 
455 	return (0);
456 }
457 
458 /*
459  * Dump current status to dump hook
460  */
461 static int
ng_ccatm_dump(node_p node)462 ng_ccatm_dump(node_p node)
463 {
464 	struct ccnode *priv = NG_NODE_PRIVATE(node);
465 	struct mbuf *m;
466 	int error;
467 
468 	priv->dump_first = priv->dump_last = NULL;
469 	error = cc_dump(priv->data, MCLBYTES, send_dump, priv);
470 	if (error != 0)
471 		return (error);
472 
473 	if ((m = priv->dump_first) != NULL) {
474 		priv->dump_first = priv->dump_last = NULL;
475 		NG_SEND_DATA_ONLY(error, priv->dump, m);
476 		return (error);
477 	}
478 	return (0);
479 }
480 
481 /*
482  * Control message
483  */
484 static int
ng_ccatm_rcvmsg(node_p node,item_p item,hook_p lasthook)485 ng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook)
486 {
487 	struct ng_mesg *resp = NULL;
488 	struct ng_mesg *msg;
489 	struct ccnode *priv = NG_NODE_PRIVATE(node);
490 	int error = 0;
491 
492 	NGI_GET_MSG(item, msg);
493 
494 	switch (msg->header.typecookie) {
495 
496 	  case NGM_CCATM_COOKIE:
497 		switch (msg->header.cmd) {
498 
499 		  case NGM_CCATM_DUMP:
500 			if (priv->dump)
501 				error = ng_ccatm_dump(node);
502 			else
503 				error = ENOTCONN;
504 			break;
505 
506 		  case NGM_CCATM_STOP:
507 		    {
508 			struct ngm_ccatm_port *arg;
509 
510 			if (msg->header.arglen != sizeof(*arg)) {
511 				error = EINVAL;
512 				break;
513 			}
514 			arg = (struct ngm_ccatm_port *)msg->data;
515 			error = cc_port_stop(priv->data, arg->port);
516 			break;
517 		    }
518 
519 		  case NGM_CCATM_START:
520 		    {
521 			struct ngm_ccatm_port *arg;
522 
523 			if (msg->header.arglen != sizeof(*arg)) {
524 				error = EINVAL;
525 				break;
526 			}
527 			arg = (struct ngm_ccatm_port *)msg->data;
528 			error = cc_port_start(priv->data, arg->port);
529 			break;
530 		    }
531 
532 		  case NGM_CCATM_GETSTATE:
533 		    {
534 			struct ngm_ccatm_port *arg;
535 			int state;
536 
537 			if (msg->header.arglen != sizeof(*arg)) {
538 				error = EINVAL;
539 				break;
540 			}
541 			arg = (struct ngm_ccatm_port *)msg->data;
542 			error = cc_port_isrunning(priv->data, arg->port,
543 			    &state);
544 			if (error == 0) {
545 				NG_MKRESPONSE(resp, msg, sizeof(uint32_t),
546 				    M_NOWAIT);
547 				if (resp == NULL) {
548 					error = ENOMEM;
549 					break;
550 				}
551 				*(uint32_t *)resp->data = state;
552 			}
553 			break;
554 		    }
555 
556 		  case NGM_CCATM_GET_ADDRESSES:
557 		   {
558 			struct ngm_ccatm_port *arg;
559 
560 			if (msg->header.arglen != sizeof(*arg)) {
561 				error = EINVAL;
562 				break;
563 			}
564 			arg = (struct ngm_ccatm_port *)msg->data;
565 			error = ng_ccatm_get_addresses(node, arg->port, msg,
566 			    &resp);
567 			break;
568 		    }
569 
570 		  case NGM_CCATM_CLEAR:
571 		    {
572 			struct ngm_ccatm_port *arg;
573 
574 			if (msg->header.arglen != sizeof(*arg)) {
575 				error = EINVAL;
576 				break;
577 			}
578 			arg = (struct ngm_ccatm_port *)msg->data;
579 			error = cc_port_clear(priv->data, arg->port);
580 			break;
581 		    }
582 
583 		  case NGM_CCATM_ADDRESS_REGISTERED:
584 		    {
585 			struct ngm_ccatm_addr_req *arg;
586 
587 			if (msg->header.arglen != sizeof(*arg)) {
588 				error = EINVAL;
589 				break;
590 			}
591 			arg = (struct ngm_ccatm_addr_req *)msg->data;
592 			error = cc_addr_register(priv->data, arg->port,
593 			    &arg->addr);
594 			break;
595 		    }
596 
597 		  case NGM_CCATM_ADDRESS_UNREGISTERED:
598 		    {
599 			struct ngm_ccatm_addr_req *arg;
600 
601 			if (msg->header.arglen != sizeof(*arg)) {
602 				error = EINVAL;
603 				break;
604 			}
605 			arg = (struct ngm_ccatm_addr_req *)msg->data;
606 			error = cc_addr_unregister(priv->data, arg->port,
607 			    &arg->addr);
608 			break;
609 		    }
610 
611 		  case NGM_CCATM_GET_PORT_PARAM:
612 		    {
613 			struct ngm_ccatm_port *arg;
614 
615 			if (msg->header.arglen != sizeof(*arg)) {
616 				error = EINVAL;
617 				break;
618 			}
619 			arg = (struct ngm_ccatm_port *)msg->data;
620 			NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info),
621 			    M_NOWAIT);
622 			if (resp == NULL) {
623 				error = ENOMEM;
624 				break;
625 			}
626 			error = cc_port_get_param(priv->data, arg->port,
627 			    (struct atm_port_info *)resp->data);
628 			if (error != 0) {
629 				free(resp, M_NETGRAPH_MSG);
630 				resp = NULL;
631 			}
632 			break;
633 		    }
634 
635 		  case NGM_CCATM_SET_PORT_PARAM:
636 		    {
637 			struct atm_port_info *arg;
638 
639 			if (msg->header.arglen != sizeof(*arg)) {
640 				error = EINVAL;
641 				break;
642 			}
643 			arg = (struct atm_port_info *)msg->data;
644 			error = cc_port_set_param(priv->data, arg);
645 			break;
646 		    }
647 
648 		  case NGM_CCATM_GET_PORTLIST:
649 		    {
650 			struct ngm_ccatm_portlist *arg;
651 			u_int n, *ports;
652 
653 			if (msg->header.arglen != 0) {
654 				error = EINVAL;
655 				break;
656 			}
657 			error = cc_port_getlist(priv->data, &n, &ports);
658 			if (error != 0)
659 				break;
660 
661 			NG_MKRESPONSE(resp, msg, sizeof(*arg) +
662 			    n * sizeof(arg->ports[0]), M_NOWAIT);
663 			if (resp == NULL) {
664 				free(ports, M_NG_CCATM);
665 				error = ENOMEM;
666 				break;
667 			}
668 			arg = (struct ngm_ccatm_portlist *)resp->data;
669 
670 			arg->nports = 0;
671 			for (arg->nports = 0; arg->nports < n; arg->nports++)
672 				arg->ports[arg->nports] = ports[arg->nports];
673 			free(ports, M_NG_CCATM);
674 			break;
675 		    }
676 
677 		  case NGM_CCATM_SETLOG:
678 		    {
679 			uint32_t log_level;
680 
681 			log_level = cc_get_log(priv->data);
682 			if (msg->header.arglen != 0) {
683 				if (msg->header.arglen != sizeof(log_level)) {
684 					error = EINVAL;
685 					break;
686 				}
687 				cc_set_log(priv->data, *(uint32_t *)msg->data);
688 			}
689 
690 			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
691 			if (resp == NULL) {
692 				error = ENOMEM;
693 				if (msg->header.arglen != 0)
694 					cc_set_log(priv->data, log_level);
695 				break;
696 			}
697 			*(uint32_t *)resp->data = log_level;
698 			break;
699 		    }
700 
701 		  case NGM_CCATM_RESET:
702 			if (msg->header.arglen != 0) {
703 				error = EINVAL;
704 				break;
705 			}
706 
707 			if (priv->hook_cnt != 0) {
708 				error = EBUSY;
709 				break;
710 			}
711 			cc_reset(priv->data);
712 			break;
713 
714 		  case NGM_CCATM_GET_EXSTAT:
715 		    {
716 			struct atm_exstatus s;
717 			struct atm_exstatus_ep *eps;
718 			struct atm_exstatus_port *ports;
719 			struct atm_exstatus_conn *conns;
720 			struct atm_exstatus_party *parties;
721 			size_t offs;
722 
723 			if (msg->header.arglen != 0) {
724 				error = EINVAL;
725 				break;
726 			}
727 			error = cc_get_extended_status(priv->data,
728 			    &s, &eps, &ports, &conns, &parties);
729 			if (error != 0)
730 				break;
731 
732 			offs = sizeof(s) + s.neps * sizeof(*eps) +
733 			    s.nports * sizeof(*ports) +
734 			    s.nconns * sizeof(*conns) +
735 			    s.nparties * sizeof(*parties);
736 
737 			NG_MKRESPONSE(resp, msg, offs, M_NOWAIT);
738 			if (resp == NULL) {
739 				error = ENOMEM;
740 				break;
741 			}
742 
743 			memcpy(resp->data, &s, sizeof(s));
744 			offs = sizeof(s);
745 
746 			memcpy(resp->data + offs, eps,
747 			    sizeof(*eps) * s.neps);
748 			offs += sizeof(*eps) * s.neps;
749 
750 			memcpy(resp->data + offs, ports,
751 			    sizeof(*ports) * s.nports);
752 			offs += sizeof(*ports) * s.nports;
753 
754 			memcpy(resp->data + offs, conns,
755 			    sizeof(*conns) * s.nconns);
756 			offs += sizeof(*conns) * s.nconns;
757 
758 			memcpy(resp->data + offs, parties,
759 			    sizeof(*parties) * s.nparties);
760 			offs += sizeof(*parties) * s.nparties;
761 
762 			free(eps, M_NG_CCATM);
763 			free(ports, M_NG_CCATM);
764 			free(conns, M_NG_CCATM);
765 			free(parties, M_NG_CCATM);
766 			break;
767 		    }
768 
769 		  default:
770 			error = EINVAL;
771 			break;
772 
773 		}
774 		break;
775 
776 	  default:
777 		error = EINVAL;
778 		break;
779 
780 	}
781 
782 	NG_RESPOND_MSG(error, node, item, resp);
783 	NG_FREE_MSG(msg);
784 	return (error);
785 }
786 
787 /************************************************************
788  *
789  * New hook arrival
790  */
791 static int
ng_ccatm_newhook(node_p node,hook_p hook,const char * name)792 ng_ccatm_newhook(node_p node, hook_p hook, const char *name)
793 {
794 	struct ccnode *priv = NG_NODE_PRIVATE(node);
795 	struct ccport *port;
796 	struct ccuser *user;
797 	struct cchook *hd;
798 	u_long lport;
799 	char *end;
800 
801 	if (strncmp(name, "uni", 3) == 0) {
802 		/*
803 		 * This is a UNI hook. Should be a new port.
804 		 */
805 		if (name[3] == '\0')
806 			return (EINVAL);
807 		lport = strtoul(name + 3, &end, 10);
808 		if (*end != '\0' || lport == 0 || lport > 0xffffffff)
809 			return (EINVAL);
810 
811 		hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
812 		if (hd == NULL)
813 			return (ENOMEM);
814 		hd->is_uni = 1;
815 		hd->node = priv;
816 		hd->hook = hook;
817 
818 		port = cc_port_create(priv->data, hd, (u_int)lport);
819 		if (port == NULL) {
820 			free(hd, M_NG_CCATM);
821 			return (ENOMEM);
822 		}
823 		hd->inst = port;
824 
825 		NG_HOOK_SET_PRIVATE(hook, hd);
826 		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni);
827 		NG_HOOK_FORCE_QUEUE(hook);
828 
829 		priv->hook_cnt++;
830 
831 		return (0);
832 	}
833 
834 	if (strcmp(name, "dump") == 0) {
835 		priv->dump = hook;
836 		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump);
837 		return (0);
838 	}
839 
840 	if (strcmp(name, "manage") == 0) {
841 		priv->manage = hook;
842 		NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage);
843 		return (0);
844 	}
845 
846 	/*
847 	 * User hook
848 	 */
849 	hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
850 	if (hd == NULL)
851 		return (ENOMEM);
852 	hd->is_uni = 0;
853 	hd->node = priv;
854 	hd->hook = hook;
855 
856 	user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook));
857 	if (user == NULL) {
858 		free(hd, M_NG_CCATM);
859 		return (ENOMEM);
860 	}
861 
862 	hd->inst = user;
863 	NG_HOOK_SET_PRIVATE(hook, hd);
864 	NG_HOOK_FORCE_QUEUE(hook);
865 
866 	priv->hook_cnt++;
867 
868 	return (0);
869 }
870 
871 /*
872  * Disconnect a hook
873  */
874 static int
ng_ccatm_disconnect(hook_p hook)875 ng_ccatm_disconnect(hook_p hook)
876 {
877 	node_p node = NG_HOOK_NODE(hook);
878 	struct ccnode *priv = NG_NODE_PRIVATE(node);
879 	struct cchook *hd = NG_HOOK_PRIVATE(hook);
880 	struct ccdata *cc;
881 
882 	if (hook == priv->dump) {
883 		priv->dump = NULL;
884 
885 	} else if (hook == priv->manage) {
886 		priv->manage = NULL;
887 		cc_unmanage(priv->data);
888 
889 	} else {
890 		if (hd->is_uni)
891 			cc_port_destroy(hd->inst, 0);
892 		else
893 			cc_user_destroy(hd->inst);
894 
895 		cc = hd->node->data;
896 
897 		free(hd, M_NG_CCATM);
898 		NG_HOOK_SET_PRIVATE(hook, NULL);
899 
900 		priv->hook_cnt--;
901 
902 		cc_work(cc);
903 	}
904 
905 	/*
906 	 * When the number of hooks drops to zero, delete the node.
907 	 */
908 	if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node))
909 		ng_rmnode_self(node);
910 
911 	return (0);
912 }
913 
914 /************************************************************
915  *
916  * Receive data from user hook
917  */
918 static int
ng_ccatm_rcvdata(hook_p hook,item_p item)919 ng_ccatm_rcvdata(hook_p hook, item_p item)
920 {
921 	struct cchook *hd = NG_HOOK_PRIVATE(hook);
922 	struct uni_msg *msg;
923 	struct mbuf *m;
924 	struct ccatm_op op;
925 	int err;
926 
927 	NGI_GET_M(item, m);
928 	NG_FREE_ITEM(item);
929 
930 	if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
931 		m_freem(m);
932 		return (err);
933 	}
934 	m_freem(m);
935 
936 	if (uni_msg_len(msg) < sizeof(op)) {
937 		printf("%s: packet too short\n", __func__);
938 		uni_msg_destroy(msg);
939 		return (EINVAL);
940 	}
941 
942 	bcopy(msg->b_rptr, &op, sizeof(op));
943 	msg->b_rptr += sizeof(op);
944 
945 	err = cc_user_signal(hd->inst, op.op, msg);
946 	cc_work(hd->node->data);
947 	return (err);
948 }
949 
950 /*
951  * Pack a header and a data area into an mbuf chain
952  */
953 static struct mbuf *
pack_buf(void * h,size_t hlen,void * t,size_t tlen)954 pack_buf(void *h, size_t hlen, void *t, size_t tlen)
955 {
956 	struct mbuf *m, *m0, *last;
957 	u_char *buf = (u_char *)t;
958 	size_t n;
959 
960 	/* header should fit into a normal mbuf */
961 	MGETHDR(m0, M_NOWAIT, MT_DATA);
962 	if (m0 == NULL)
963 		return NULL;
964 
965 	KASSERT(hlen <= MHLEN, ("hlen > MHLEN"));
966 
967 	bcopy(h, m0->m_data, hlen);
968 	m0->m_len = hlen;
969 	m0->m_pkthdr.len = hlen;
970 
971 	last = m0;
972 	while ((n = tlen) != 0) {
973 		if (n > MLEN) {
974 			m = m_getcl(M_NOWAIT, MT_DATA, 0);
975 			if (n > MCLBYTES)
976 				n = MCLBYTES;
977 		} else
978 			MGET(m, M_NOWAIT, MT_DATA);
979 
980 		if(m == NULL)
981 			goto drop;
982 
983 		last->m_next = m;
984 		last = m;
985 
986 		bcopy(buf, m->m_data, n);
987 		buf += n;
988 		tlen -= n;
989 		m->m_len = n;
990 		m0->m_pkthdr.len += n;
991 	}
992 
993 	return (m0);
994 
995   drop:
996 	m_freem(m0);
997 	return NULL;
998 }
999 
1000 /*
1001  * Send an indication to the user.
1002  */
1003 static void
ng_ccatm_send_user(struct ccuser * user,void * uarg,u_int op,void * val,size_t len)1004 ng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op,
1005     void *val, size_t len)
1006 {
1007 	struct cchook *hd = uarg;
1008 	struct mbuf *m;
1009 	struct ccatm_op	h;
1010 	int error;
1011 
1012 	h.op = op;
1013 	m = pack_buf(&h, sizeof(h), val, len);
1014 	if (m == NULL)
1015 		return;
1016 
1017 	NG_SEND_DATA_ONLY(error, hd->hook, m);
1018 	if (error != 0)
1019 		printf("%s: error=%d\n", __func__, error);
1020 }
1021 
1022 /*
1023  * Send a response to the user.
1024  */
1025 static void
ng_ccatm_respond_user(struct ccuser * user,void * uarg,int err,u_int data,void * val,size_t len)1026 ng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data,
1027     void *val, size_t len)
1028 {
1029 	struct cchook *hd = uarg;
1030 	struct mbuf *m;
1031 	struct {
1032 		struct ccatm_op	op;
1033 		struct atm_resp resp;
1034 	} resp;
1035 	int error;
1036 
1037 	resp.op.op = ATMOP_RESP;
1038 	resp.resp.resp = err;
1039 	resp.resp.data = data;
1040 	m = pack_buf(&resp, sizeof(resp), val, len);
1041 	if (m == NULL)
1042 		return;
1043 
1044 	NG_SEND_DATA_ONLY(error, hd->hook, m);
1045 	if (error != 0)
1046 		printf("%s: error=%d\n", __func__, error);
1047 }
1048 
1049 /*
1050  * Receive data from UNI.
1051  */
1052 static int
ng_ccatm_rcvuni(hook_p hook,item_p item)1053 ng_ccatm_rcvuni(hook_p hook, item_p item)
1054 {
1055 	struct cchook *hd = NG_HOOK_PRIVATE(hook);
1056 	struct uni_msg *msg;
1057 	struct uni_arg arg;
1058 	struct mbuf *m;
1059 	int err;
1060 
1061 	NGI_GET_M(item, m);
1062 	NG_FREE_ITEM(item);
1063 
1064 	if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
1065 		m_freem(m);
1066 		return (err);
1067 	}
1068 	m_freem(m);
1069 
1070 	if (uni_msg_len(msg) < sizeof(arg)) {
1071 		printf("%s: packet too short\n", __func__);
1072 		uni_msg_destroy(msg);
1073 		return (EINVAL);
1074 	}
1075 
1076 	bcopy(msg->b_rptr, &arg, sizeof(arg));
1077 	msg->b_rptr += sizeof(arg);
1078 
1079 	if (arg.sig == UNIAPI_ERROR) {
1080 		if (uni_msg_len(msg) != sizeof(struct uniapi_error)) {
1081 			printf("%s: bad UNIAPI_ERROR size %zu\n", __func__,
1082 			    uni_msg_len(msg));
1083 			uni_msg_destroy(msg);
1084 			return (EINVAL);
1085 		}
1086 		err = cc_uni_response(hd->inst, arg.cookie,
1087 		    ((struct uniapi_error *)msg->b_rptr)->reason,
1088 		    ((struct uniapi_error *)msg->b_rptr)->state);
1089 		uni_msg_destroy(msg);
1090 	} else
1091 		err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg);
1092 
1093 	cc_work(hd->node->data);
1094 	return (err);
1095 }
1096 
1097 /*
1098  * Uarg is the port's uarg.
1099  */
1100 static void
ng_ccatm_send_uni(struct ccconn * conn,void * uarg,u_int op,u_int cookie,struct uni_msg * msg)1101 ng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie,
1102     struct uni_msg *msg)
1103 {
1104 	struct cchook *hd = uarg;
1105 	struct uni_arg arg;
1106 	struct mbuf *m;
1107 	int error;
1108 
1109 	arg.sig = op;
1110 	arg.cookie = cookie;
1111 
1112 	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1113 	uni_msg_destroy(msg);
1114 	if (m == NULL)
1115 		return;
1116 
1117 	NG_SEND_DATA_ONLY(error, hd->hook, m);
1118 	if (error != 0)
1119 		printf("%s: error=%d\n", __func__, error);
1120 }
1121 
1122 /*
1123  * Send a global message to the UNI
1124  */
1125 static void
ng_ccatm_send_uni_glob(struct ccport * port,void * uarg,u_int op,u_int cookie,struct uni_msg * msg)1126 ng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie,
1127     struct uni_msg *msg)
1128 {
1129 	struct cchook *hd = uarg;
1130 	struct uni_arg arg;
1131 	struct mbuf *m;
1132 	int error;
1133 
1134 	arg.sig = op;
1135 	arg.cookie = cookie;
1136 
1137 	m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1138 	if (msg != NULL)
1139 		uni_msg_destroy(msg);
1140 	if (m == NULL)
1141 		return;
1142 
1143 	NG_SEND_DATA_ONLY(error, hd->hook, m);
1144 	if (error != 0)
1145 		printf("%s: error=%d\n", __func__, error);
1146 }
1147 /*
1148  * Receive from ILMID
1149  */
1150 static int
ng_ccatm_rcvmanage(hook_p hook,item_p item)1151 ng_ccatm_rcvmanage(hook_p hook, item_p item)
1152 {
1153 	NG_FREE_ITEM(item);
1154 	return (0);
1155 }
1156 
1157 static int
ng_ccatm_rcvdump(hook_p hook,item_p item)1158 ng_ccatm_rcvdump(hook_p hook, item_p item)
1159 {
1160 	NG_FREE_ITEM(item);
1161 	return (0);
1162 }
1163 
1164 static void
ng_ccatm_log(const char * fmt,...)1165 ng_ccatm_log(const char *fmt, ...)
1166 {
1167 	va_list ap;
1168 
1169 	va_start(ap, fmt);
1170 	vprintf(fmt, ap);
1171 	printf("\n");
1172 	va_end(ap);
1173 }
1174 
1175 /*
1176  * Loading and unloading of node type
1177  */
1178 static int
ng_ccatm_mod_event(module_t mod,int event,void * data)1179 ng_ccatm_mod_event(module_t mod, int event, void *data)
1180 {
1181 	int error = 0;
1182 
1183 	switch (event) {
1184 
1185 	  case MOD_LOAD:
1186 		break;
1187 
1188 	  case MOD_UNLOAD:
1189 		break;
1190 
1191 	  default:
1192 		error = EOPNOTSUPP;
1193 		break;
1194 	}
1195 	return (error);
1196 }
1197