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