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