Vendor import of netgraph from FreeBSD-current 20080626
[dragonfly.git] / sys / netgraph7 / atm / ccatm / ng_ccatm.c
blob404f54e7c87d49c1b67173cd47b801a67c658928
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.
9 * Author: Harti Brandt <harti@freebsd.org>
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:
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.
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.
33 * $FreeBSD: src/sys/netgraph/atm/ccatm/ng_ccatm.c,v 1.3 2006/09/30 12:37:43 netchild Exp $
35 * ATM call control and API
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: src/sys/netgraph/atm/ccatm/ng_ccatm.c,v 1.3 2006/09/30 12:37:43 netchild Exp $");
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>
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>
65 MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1);
67 MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node");
70 * Command structure parsing
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
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
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
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
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
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
121 /* ADDRESS var-array */
122 static int
123 ng_ccatm_addr_req_array_getlen(const struct ng_parse_type *type,
124 const u_char *start, const u_char *buf)
126 const struct ngm_ccatm_get_addresses *p;
128 p = (const struct ngm_ccatm_get_addresses *)
129 (buf - offsetof(struct ngm_ccatm_get_addresses, addr));
130 return (p->count);
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
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
147 /* Port array */
148 static int
149 ng_ccatm_port_array_getlen(const struct ng_parse_type *type,
150 const u_char *start, const u_char *buf)
152 const struct ngm_ccatm_portlist *p;
154 p = (const struct ngm_ccatm_portlist *)
155 (buf - offsetof(struct ngm_ccatm_portlist, ports));
156 return (p->nports);
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
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
174 * Command list
176 static const struct ng_cmdlist ng_ccatm_cmdlist[] = {
178 NGM_CCATM_COOKIE,
179 NGM_CCATM_DUMP,
180 "dump",
181 NULL,
182 NULL
185 NGM_CCATM_COOKIE,
186 NGM_CCATM_STOP,
187 "stop",
188 &ng_ccatm_port_type,
189 NULL
192 NGM_CCATM_COOKIE,
193 NGM_CCATM_START,
194 "start",
195 &ng_ccatm_port_type,
196 NULL
199 NGM_CCATM_COOKIE,
200 NGM_CCATM_GETSTATE,
201 "getstate",
202 &ng_ccatm_port_type,
203 &ng_parse_uint32_type
206 NGM_CCATM_COOKIE,
207 NGM_CCATM_GET_ADDRESSES,
208 "get_addresses",
209 &ng_ccatm_port_type,
210 &ng_ccatm_get_addresses_type
213 NGM_CCATM_COOKIE,
214 NGM_CCATM_CLEAR,
215 "clear",
216 &ng_ccatm_port_type,
217 NULL
220 NGM_CCATM_COOKIE,
221 NGM_CCATM_ADDRESS_REGISTERED,
222 "address_reg",
223 &ng_ccatm_addr_req_type,
224 NULL
227 NGM_CCATM_COOKIE,
228 NGM_CCATM_ADDRESS_UNREGISTERED,
229 "address_unreg",
230 &ng_ccatm_addr_req_type,
231 NULL
234 NGM_CCATM_COOKIE,
235 NGM_CCATM_SET_PORT_PARAM,
236 "set_port_param",
237 &ng_ccatm_atm_port_type,
238 NULL
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,
248 NGM_CCATM_COOKIE,
249 NGM_CCATM_GET_PORTLIST,
250 "get_portlist",
251 NULL,
252 &ng_ccatm_portlist_type,
255 NGM_CCATM_COOKIE,
256 NGM_CCATM_SETLOG,
257 "setlog",
258 &ng_parse_hint32_type,
259 &ng_parse_hint32_type,
262 NGM_CCATM_COOKIE,
263 NGM_CCATM_RESET,
264 "reset",
265 NULL,
266 NULL,
268 { 0 }
272 * Module data
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 *);
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,
294 NETGRAPH_INIT(ccatm, &ng_ccatm_typestruct);
296 static ng_rcvdata_t ng_ccatm_rcvuni;
297 static ng_rcvdata_t ng_ccatm_rcvdump;
298 static ng_rcvdata_t ng_ccatm_rcvmanage;
301 * Private node data.
303 struct ccnode {
304 node_p node; /* the owning node */
305 hook_p dump; /* dump hook */
306 hook_p manage; /* hook to ILMI */
308 struct ccdata *data;
309 struct mbuf *dump_first;
310 struct mbuf *dump_last; /* first and last mbuf when dumping */
312 u_int hook_cnt; /* count user and port hooks */
316 * Private UNI hook data
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 */
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);
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,
342 /************************************************************
344 * Create a new node
346 static int
347 ng_ccatm_constructor(node_p node)
349 struct ccnode *priv;
351 priv = malloc(sizeof(*priv), M_NG_CCATM, M_NOWAIT | M_ZERO);
352 if (priv == NULL)
353 return (ENOMEM);
355 priv->node = node;
356 priv->data = cc_create(&cc_funcs);
357 if (priv->data == NULL) {
358 free(priv, M_NG_CCATM);
359 return (ENOMEM);
362 NG_NODE_SET_PRIVATE(node, priv);
364 return (0);
368 * Destroy a node. The user list is empty here, because all hooks are
369 * previously disconnected. The connection lists may not be empty, because
370 * connections may be waiting for responses from the stack. This also means,
371 * that no orphaned connections will be made by the port_destroy routine.
373 static int
374 ng_ccatm_shutdown(node_p node)
376 struct ccnode *priv = NG_NODE_PRIVATE(node);
378 cc_destroy(priv->data);
380 free(priv, M_NG_CCATM);
381 NG_NODE_SET_PRIVATE(node, NULL);
383 NG_NODE_UNREF(node);
385 return (0);
389 * Retrieve the registered addresses for one port or all ports.
390 * Returns an error code or 0 on success.
392 static int
393 ng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg,
394 struct ng_mesg **resp)
396 struct ccnode *priv = NG_NODE_PRIVATE(node);
397 struct uni_addr *addrs;
398 u_int *ports;
399 struct ngm_ccatm_get_addresses *list;
400 u_int count, i;
401 size_t len;
402 int err;
404 err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count);
405 if (err != 0)
406 return (err);
408 len = sizeof(*list) + count * sizeof(list->addr[0]);
409 NG_MKRESPONSE(*resp, msg, len, M_NOWAIT);
410 if (*resp == NULL) {
411 free(addrs, M_NG_CCATM);
412 free(ports, M_NG_CCATM);
413 return (ENOMEM);
415 list = (struct ngm_ccatm_get_addresses *)(*resp)->data;
417 list->count = count;
418 for (i = 0; i < count; i++) {
419 list->addr[i].port = ports[i];
420 list->addr[i].addr = addrs[i];
423 free(addrs, M_NG_CCATM);
424 free(ports, M_NG_CCATM);
426 return (0);
430 * Dumper function. Pack the data into an mbuf chain.
432 static int
433 send_dump(struct ccdata *data, void *uarg, const char *buf)
435 struct mbuf *m;
436 struct ccnode *priv = uarg;
438 if (priv->dump == NULL) {
439 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
440 if (m == NULL)
441 return (ENOBUFS);
442 priv->dump_first = priv->dump_last = m;
443 m->m_pkthdr.len = 0;
444 } else {
445 m = m_getcl(M_DONTWAIT, MT_DATA, 0);
446 if (m == 0) {
447 m_freem(priv->dump_first);
448 return (ENOBUFS);
450 priv->dump_last->m_next = m;
451 priv->dump_last = m;
454 strcpy(m->m_data, buf);
455 priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf));
457 return (0);
461 * Dump current status to dump hook
463 static int
464 ng_ccatm_dump(node_p node)
466 struct ccnode *priv = NG_NODE_PRIVATE(node);
467 struct mbuf *m;
468 int error;
470 priv->dump_first = priv->dump_last = NULL;
471 error = cc_dump(priv->data, MCLBYTES, send_dump, priv);
472 if (error != 0)
473 return (error);
475 if ((m = priv->dump_first) != NULL) {
476 priv->dump_first = priv->dump_last = NULL;
477 NG_SEND_DATA_ONLY(error, priv->dump, m);
478 return (error);
480 return (0);
484 * Control message
486 static int
487 ng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook)
489 struct ng_mesg *resp = NULL;
490 struct ng_mesg *msg;
491 struct ccnode *priv = NG_NODE_PRIVATE(node);
492 int error = 0;
494 NGI_GET_MSG(item, msg);
496 switch (msg->header.typecookie) {
498 case NGM_CCATM_COOKIE:
499 switch (msg->header.cmd) {
501 case NGM_CCATM_DUMP:
502 if (priv->dump)
503 error = ng_ccatm_dump(node);
504 else
505 error = ENOTCONN;
506 break;
508 case NGM_CCATM_STOP:
510 struct ngm_ccatm_port *arg;
512 if (msg->header.arglen != sizeof(*arg)) {
513 error = EINVAL;
514 break;
516 arg = (struct ngm_ccatm_port *)msg->data;
517 error = cc_port_stop(priv->data, arg->port);
518 break;
521 case NGM_CCATM_START:
523 struct ngm_ccatm_port *arg;
525 if (msg->header.arglen != sizeof(*arg)) {
526 error = EINVAL;
527 break;
529 arg = (struct ngm_ccatm_port *)msg->data;
530 error = cc_port_start(priv->data, arg->port);
531 break;
534 case NGM_CCATM_GETSTATE:
536 struct ngm_ccatm_port *arg;
537 int state;
539 if (msg->header.arglen != sizeof(*arg)) {
540 error = EINVAL;
541 break;
543 arg = (struct ngm_ccatm_port *)msg->data;
544 error = cc_port_isrunning(priv->data, arg->port,
545 &state);
546 if (error == 0) {
547 NG_MKRESPONSE(resp, msg, sizeof(uint32_t),
548 M_NOWAIT);
549 if (resp == NULL) {
550 error = ENOMEM;
551 break;
553 *(uint32_t *)resp->data = state;
555 break;
558 case NGM_CCATM_GET_ADDRESSES:
560 struct ngm_ccatm_port *arg;
562 if (msg->header.arglen != sizeof(*arg)) {
563 error = EINVAL;
564 break;
566 arg = (struct ngm_ccatm_port *)msg->data;
567 error = ng_ccatm_get_addresses(node, arg->port, msg,
568 &resp);
569 break;
572 case NGM_CCATM_CLEAR:
574 struct ngm_ccatm_port *arg;
576 if (msg->header.arglen != sizeof(*arg)) {
577 error = EINVAL;
578 break;
580 arg = (struct ngm_ccatm_port *)msg->data;
581 error = cc_port_clear(priv->data, arg->port);
582 break;
585 case NGM_CCATM_ADDRESS_REGISTERED:
587 struct ngm_ccatm_addr_req *arg;
589 if (msg->header.arglen != sizeof(*arg)) {
590 error = EINVAL;
591 break;
593 arg = (struct ngm_ccatm_addr_req *)msg->data;
594 error = cc_addr_register(priv->data, arg->port,
595 &arg->addr);
596 break;
599 case NGM_CCATM_ADDRESS_UNREGISTERED:
601 struct ngm_ccatm_addr_req *arg;
603 if (msg->header.arglen != sizeof(*arg)) {
604 error = EINVAL;
605 break;
607 arg = (struct ngm_ccatm_addr_req *)msg->data;
608 error = cc_addr_unregister(priv->data, arg->port,
609 &arg->addr);
610 break;
613 case NGM_CCATM_GET_PORT_PARAM:
615 struct ngm_ccatm_port *arg;
617 if (msg->header.arglen != sizeof(*arg)) {
618 error = EINVAL;
619 break;
621 arg = (struct ngm_ccatm_port *)msg->data;
622 NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info),
623 M_NOWAIT);
624 if (resp == NULL) {
625 error = ENOMEM;
626 break;
628 error = cc_port_get_param(priv->data, arg->port,
629 (struct atm_port_info *)resp->data);
630 if (error != 0) {
631 free(resp, M_NETGRAPH_MSG);
632 resp = NULL;
634 break;
637 case NGM_CCATM_SET_PORT_PARAM:
639 struct atm_port_info *arg;
641 if (msg->header.arglen != sizeof(*arg)) {
642 error = EINVAL;
643 break;
645 arg = (struct atm_port_info *)msg->data;
646 error = cc_port_set_param(priv->data, arg);
647 break;
650 case NGM_CCATM_GET_PORTLIST:
652 struct ngm_ccatm_portlist *arg;
653 u_int n, *ports;
655 if (msg->header.arglen != 0) {
656 error = EINVAL;
657 break;
659 error = cc_port_getlist(priv->data, &n, &ports);
660 if (error != 0)
661 break;
663 NG_MKRESPONSE(resp, msg, sizeof(*arg) +
664 n * sizeof(arg->ports[0]), M_NOWAIT);
665 if (resp == NULL) {
666 free(ports, M_NG_CCATM);
667 error = ENOMEM;
668 break;
670 arg = (struct ngm_ccatm_portlist *)resp->data;
672 arg->nports = 0;
673 for (arg->nports = 0; arg->nports < n; arg->nports++)
674 arg->ports[arg->nports] = ports[arg->nports];
675 free(ports, M_NG_CCATM);
676 break;
679 case NGM_CCATM_SETLOG:
681 uint32_t log_level;
683 log_level = cc_get_log(priv->data);
684 if (msg->header.arglen != 0) {
685 if (msg->header.arglen != sizeof(log_level)) {
686 error = EINVAL;
687 break;
689 cc_set_log(priv->data, *(uint32_t *)msg->data);
692 NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
693 if (resp == NULL) {
694 error = ENOMEM;
695 if (msg->header.arglen != 0)
696 cc_set_log(priv->data, log_level);
697 break;
699 *(uint32_t *)resp->data = log_level;
700 break;
703 case NGM_CCATM_RESET:
704 if (msg->header.arglen != 0) {
705 error = EINVAL;
706 break;
709 if (priv->hook_cnt != 0) {
710 error = EBUSY;
711 break;
713 cc_reset(priv->data);
714 break;
716 case NGM_CCATM_GET_EXSTAT:
718 struct atm_exstatus s;
719 struct atm_exstatus_ep *eps;
720 struct atm_exstatus_port *ports;
721 struct atm_exstatus_conn *conns;
722 struct atm_exstatus_party *parties;
723 size_t offs;
725 if (msg->header.arglen != 0) {
726 error = EINVAL;
727 break;
729 error = cc_get_extended_status(priv->data,
730 &s, &eps, &ports, &conns, &parties);
731 if (error != 0)
732 break;
734 offs = sizeof(s) + s.neps * sizeof(*eps) +
735 s.nports * sizeof(*ports) +
736 s.nconns * sizeof(*conns) +
737 s.nparties * sizeof(*parties);
739 NG_MKRESPONSE(resp, msg, offs, M_NOWAIT);
740 if (resp == NULL) {
741 error = ENOMEM;
742 break;
745 memcpy(resp->data, &s, sizeof(s));
746 offs = sizeof(s);
748 memcpy(resp->data + offs, eps,
749 sizeof(*eps) * s.neps);
750 offs += sizeof(*eps) * s.neps;
752 memcpy(resp->data + offs, ports,
753 sizeof(*ports) * s.nports);
754 offs += sizeof(*ports) * s.nports;
756 memcpy(resp->data + offs, conns,
757 sizeof(*conns) * s.nconns);
758 offs += sizeof(*conns) * s.nconns;
760 memcpy(resp->data + offs, parties,
761 sizeof(*parties) * s.nparties);
762 offs += sizeof(*parties) * s.nparties;
764 free(eps, M_NG_CCATM);
765 free(ports, M_NG_CCATM);
766 free(conns, M_NG_CCATM);
767 free(parties, M_NG_CCATM);
768 break;
771 default:
772 error = EINVAL;
773 break;
776 break;
778 default:
779 error = EINVAL;
780 break;
784 NG_RESPOND_MSG(error, node, item, resp);
785 NG_FREE_MSG(msg);
786 return (error);
789 /************************************************************
791 * New hook arrival
793 static int
794 ng_ccatm_newhook(node_p node, hook_p hook, const char *name)
796 struct ccnode *priv = NG_NODE_PRIVATE(node);
797 struct ccport *port;
798 struct ccuser *user;
799 struct cchook *hd;
800 u_long lport;
801 char *end;
803 if (strncmp(name, "uni", 3) == 0) {
805 * This is a UNI hook. Should be a new port.
807 if (name[3] == '\0')
808 return (EINVAL);
809 lport = strtoul(name + 3, &end, 10);
810 if (*end != '\0' || lport == 0 || lport > 0xffffffff)
811 return (EINVAL);
813 hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
814 if (hd == NULL)
815 return (ENOMEM);
816 hd->is_uni = 1;
817 hd->node = priv;
818 hd->hook = hook;
820 port = cc_port_create(priv->data, hd, (u_int)lport);
821 if (port == NULL) {
822 free(hd, M_NG_CCATM);
823 return (ENOMEM);
825 hd->inst = port;
827 NG_HOOK_SET_PRIVATE(hook, hd);
828 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni);
829 NG_HOOK_FORCE_QUEUE(hook);
831 priv->hook_cnt++;
833 return (0);
836 if (strcmp(name, "dump") == 0) {
837 priv->dump = hook;
838 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump);
839 return (0);
842 if (strcmp(name, "manage") == 0) {
843 priv->manage = hook;
844 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage);
845 return (0);
849 * User hook
851 hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
852 if (hd == NULL)
853 return (ENOMEM);
854 hd->is_uni = 0;
855 hd->node = priv;
856 hd->hook = hook;
858 user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook));
859 if (user == NULL) {
860 free(hd, M_NG_CCATM);
861 return (ENOMEM);
864 hd->inst = user;
865 NG_HOOK_SET_PRIVATE(hook, hd);
866 NG_HOOK_FORCE_QUEUE(hook);
868 priv->hook_cnt++;
870 return (0);
874 * Disconnect a hook
876 static int
877 ng_ccatm_disconnect(hook_p hook)
879 node_p node = NG_HOOK_NODE(hook);
880 struct ccnode *priv = NG_NODE_PRIVATE(node);
881 struct cchook *hd = NG_HOOK_PRIVATE(hook);
882 struct ccdata *cc;
884 if (hook == priv->dump) {
885 priv->dump = NULL;
887 } else if (hook == priv->manage) {
888 priv->manage = NULL;
889 cc_unmanage(priv->data);
891 } else {
892 if (hd->is_uni)
893 cc_port_destroy(hd->inst, 0);
894 else
895 cc_user_destroy(hd->inst);
897 cc = hd->node->data;
899 free(hd, M_NG_CCATM);
900 NG_HOOK_SET_PRIVATE(hook, NULL);
902 priv->hook_cnt--;
904 cc_work(cc);
908 * When the number of hooks drops to zero, delete the node.
910 if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node))
911 ng_rmnode_self(node);
913 return (0);
916 /************************************************************
918 * Receive data from user hook
920 static int
921 ng_ccatm_rcvdata(hook_p hook, item_p item)
923 struct cchook *hd = NG_HOOK_PRIVATE(hook);
924 struct uni_msg *msg;
925 struct mbuf *m;
926 struct ccatm_op op;
927 int err;
929 NGI_GET_M(item, m);
930 NG_FREE_ITEM(item);
932 if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
933 m_freem(m);
934 return (err);
936 m_freem(m);
938 if (uni_msg_len(msg) < sizeof(op)) {
939 printf("%s: packet too short\n", __func__);
940 uni_msg_destroy(msg);
941 return (EINVAL);
944 bcopy(msg->b_rptr, &op, sizeof(op));
945 msg->b_rptr += sizeof(op);
947 err = cc_user_signal(hd->inst, op.op, msg);
948 cc_work(hd->node->data);
949 return (err);
953 * Pack a header and a data area into an mbuf chain
955 static struct mbuf *
956 pack_buf(void *h, size_t hlen, void *t, size_t tlen)
958 struct mbuf *m, *m0, *last;
959 u_char *buf = (u_char *)t;
960 size_t n;
962 /* header should fit into a normal mbuf */
963 MGETHDR(m0, M_NOWAIT, MT_DATA);
964 if (m0 == NULL)
965 return NULL;
967 KASSERT(hlen <= MHLEN, ("hlen > MHLEN"));
969 bcopy(h, m0->m_data, hlen);
970 m0->m_len = hlen;
971 m0->m_pkthdr.len = hlen;
973 last = m0;
974 while ((n = tlen) != 0) {
975 if (n > MLEN) {
976 m = m_getcl(M_NOWAIT, MT_DATA, 0);
977 if (n > MCLBYTES)
978 n = MCLBYTES;
979 } else
980 MGET(m, M_NOWAIT, MT_DATA);
982 if(m == NULL)
983 goto drop;
985 last->m_next = m;
986 last = m;
988 bcopy(buf, m->m_data, n);
989 buf += n;
990 tlen -= n;
991 m->m_len = n;
992 m0->m_pkthdr.len += n;
995 return (m0);
997 drop:
998 m_freem(m0);
999 return NULL;
1003 * Send an indication to the user.
1005 static void
1006 ng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op,
1007 void *val, size_t len)
1009 struct cchook *hd = uarg;
1010 struct mbuf *m;
1011 struct ccatm_op h;
1012 int error;
1014 h.op = op;
1015 m = pack_buf(&h, sizeof(h), val, len);
1016 if (m == NULL)
1017 return;
1019 NG_SEND_DATA_ONLY(error, hd->hook, m);
1020 if (error != 0)
1021 printf("%s: error=%d\n", __func__, error);
1025 * Send a response to the user.
1027 static void
1028 ng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data,
1029 void *val, size_t len)
1031 struct cchook *hd = uarg;
1032 struct mbuf *m;
1033 struct {
1034 struct ccatm_op op;
1035 struct atm_resp resp;
1036 } resp;
1037 int error;
1039 resp.op.op = ATMOP_RESP;
1040 resp.resp.resp = err;
1041 resp.resp.data = data;
1042 m = pack_buf(&resp, sizeof(resp), val, len);
1043 if (m == NULL)
1044 return;
1046 NG_SEND_DATA_ONLY(error, hd->hook, m);
1047 if (error != 0)
1048 printf("%s: error=%d\n", __func__, error);
1052 * Receive data from UNI.
1054 static int
1055 ng_ccatm_rcvuni(hook_p hook, item_p item)
1057 struct cchook *hd = NG_HOOK_PRIVATE(hook);
1058 struct uni_msg *msg;
1059 struct uni_arg arg;
1060 struct mbuf *m;
1061 int err;
1063 NGI_GET_M(item, m);
1064 NG_FREE_ITEM(item);
1066 if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
1067 m_freem(m);
1068 return (err);
1070 m_freem(m);
1072 if (uni_msg_len(msg) < sizeof(arg)) {
1073 printf("%s: packet too short\n", __func__);
1074 uni_msg_destroy(msg);
1075 return (EINVAL);
1078 bcopy(msg->b_rptr, &arg, sizeof(arg));
1079 msg->b_rptr += sizeof(arg);
1081 if (arg.sig == UNIAPI_ERROR) {
1082 if (uni_msg_len(msg) != sizeof(struct uniapi_error)) {
1083 printf("%s: bad UNIAPI_ERROR size %zu\n", __func__,
1084 uni_msg_len(msg));
1085 uni_msg_destroy(msg);
1086 return (EINVAL);
1088 err = cc_uni_response(hd->inst, arg.cookie,
1089 ((struct uniapi_error *)msg->b_rptr)->reason,
1090 ((struct uniapi_error *)msg->b_rptr)->state);
1091 uni_msg_destroy(msg);
1092 } else
1093 err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg);
1095 cc_work(hd->node->data);
1096 return (err);
1100 * Uarg is the port's uarg.
1102 static void
1103 ng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie,
1104 struct uni_msg *msg)
1106 struct cchook *hd = uarg;
1107 struct uni_arg arg;
1108 struct mbuf *m;
1109 int error;
1111 arg.sig = op;
1112 arg.cookie = cookie;
1114 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1115 uni_msg_destroy(msg);
1116 if (m == NULL)
1117 return;
1119 NG_SEND_DATA_ONLY(error, hd->hook, m);
1120 if (error != 0)
1121 printf("%s: error=%d\n", __func__, error);
1125 * Send a global message to the UNI
1127 static void
1128 ng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie,
1129 struct uni_msg *msg)
1131 struct cchook *hd = uarg;
1132 struct uni_arg arg;
1133 struct mbuf *m;
1134 int error;
1136 arg.sig = op;
1137 arg.cookie = cookie;
1139 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1140 if (msg != NULL)
1141 uni_msg_destroy(msg);
1142 if (m == NULL)
1143 return;
1145 NG_SEND_DATA_ONLY(error, hd->hook, m);
1146 if (error != 0)
1147 printf("%s: error=%d\n", __func__, error);
1150 * Receive from ILMID
1152 static int
1153 ng_ccatm_rcvmanage(hook_p hook, item_p item)
1155 NG_FREE_ITEM(item);
1156 return (0);
1159 static int
1160 ng_ccatm_rcvdump(hook_p hook, item_p item)
1162 NG_FREE_ITEM(item);
1163 return (0);
1166 static void
1167 ng_ccatm_log(const char *fmt, ...)
1169 va_list ap;
1171 va_start(ap, fmt);
1172 vprintf(fmt, ap);
1173 printf("\n");
1174 va_end(ap);
1178 * Loading and unloading of node type
1180 static int
1181 ng_ccatm_mod_event(module_t mod, int event, void *data)
1183 int s;
1184 int error = 0;
1186 s = splnet();
1187 switch (event) {
1189 case MOD_LOAD:
1190 break;
1192 case MOD_UNLOAD:
1193 break;
1195 default:
1196 error = EOPNOTSUPP;
1197 break;
1199 splx(s);
1200 return (error);