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