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