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