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 <[email protected]>
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
ng_ccatm_addr_req_array_getlen(const struct ng_parse_type * type,const u_char * start,const u_char * buf)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
ng_ccatm_port_array_getlen(const struct ng_parse_type * type,const u_char * start,const u_char * buf)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
ng_ccatm_constructor(node_p node)347 ng_ccatm_constructor(node_p node)
348 {
349 struct ccnode *priv;
350
351 priv = malloc(sizeof(*priv), M_NG_CCATM, M_WAITOK | M_ZERO);
352
353 priv->node = node;
354 priv->data = cc_create(&cc_funcs);
355 if (priv->data == NULL) {
356 free(priv, M_NG_CCATM);
357 return (ENOMEM);
358 }
359
360 NG_NODE_SET_PRIVATE(node, priv);
361
362 return (0);
363 }
364
365 /*
366 * Destroy a node. The user list is empty here, because all hooks are
367 * previously disconnected. The connection lists may not be empty, because
368 * connections may be waiting for responses from the stack. This also means,
369 * that no orphaned connections will be made by the port_destroy routine.
370 */
371 static int
ng_ccatm_shutdown(node_p node)372 ng_ccatm_shutdown(node_p node)
373 {
374 struct ccnode *priv = NG_NODE_PRIVATE(node);
375
376 cc_destroy(priv->data);
377
378 free(priv, M_NG_CCATM);
379 NG_NODE_SET_PRIVATE(node, NULL);
380
381 NG_NODE_UNREF(node);
382
383 return (0);
384 }
385
386 /*
387 * Retrieve the registered addresses for one port or all ports.
388 * Returns an error code or 0 on success.
389 */
390 static int
ng_ccatm_get_addresses(node_p node,uint32_t portno,struct ng_mesg * msg,struct ng_mesg ** resp)391 ng_ccatm_get_addresses(node_p node, uint32_t portno, struct ng_mesg *msg,
392 struct ng_mesg **resp)
393 {
394 struct ccnode *priv = NG_NODE_PRIVATE(node);
395 struct uni_addr *addrs;
396 u_int *ports;
397 struct ngm_ccatm_get_addresses *list;
398 u_int count, i;
399 size_t len;
400 int err;
401
402 err = cc_get_addrs(priv->data, portno, &addrs, &ports, &count);
403 if (err != 0)
404 return (err);
405
406 len = sizeof(*list) + count * sizeof(list->addr[0]);
407 NG_MKRESPONSE(*resp, msg, len, M_NOWAIT);
408 if (*resp == NULL) {
409 free(addrs, M_NG_CCATM);
410 free(ports, M_NG_CCATM);
411 return (ENOMEM);
412 }
413 list = (struct ngm_ccatm_get_addresses *)(*resp)->data;
414
415 list->count = count;
416 for (i = 0; i < count; i++) {
417 list->addr[i].port = ports[i];
418 list->addr[i].addr = addrs[i];
419 }
420
421 free(addrs, M_NG_CCATM);
422 free(ports, M_NG_CCATM);
423
424 return (0);
425 }
426
427 /*
428 * Dumper function. Pack the data into an mbuf chain.
429 */
430 static int
send_dump(struct ccdata * data,void * uarg,const char * buf)431 send_dump(struct ccdata *data, void *uarg, const char *buf)
432 {
433 struct mbuf *m;
434 struct ccnode *priv = uarg;
435
436 if (priv->dump == NULL) {
437 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
438 if (m == NULL)
439 return (ENOBUFS);
440 priv->dump_first = priv->dump_last = m;
441 m->m_pkthdr.len = 0;
442 } else {
443 m = m_getcl(M_NOWAIT, MT_DATA, 0);
444 if (m == NULL) {
445 m_freem(priv->dump_first);
446 return (ENOBUFS);
447 }
448 priv->dump_last->m_next = m;
449 priv->dump_last = m;
450 }
451
452 strcpy(m->m_data, buf);
453 priv->dump_first->m_pkthdr.len += (m->m_len = strlen(buf));
454
455 return (0);
456 }
457
458 /*
459 * Dump current status to dump hook
460 */
461 static int
ng_ccatm_dump(node_p node)462 ng_ccatm_dump(node_p node)
463 {
464 struct ccnode *priv = NG_NODE_PRIVATE(node);
465 struct mbuf *m;
466 int error;
467
468 priv->dump_first = priv->dump_last = NULL;
469 error = cc_dump(priv->data, MCLBYTES, send_dump, priv);
470 if (error != 0)
471 return (error);
472
473 if ((m = priv->dump_first) != NULL) {
474 priv->dump_first = priv->dump_last = NULL;
475 NG_SEND_DATA_ONLY(error, priv->dump, m);
476 return (error);
477 }
478 return (0);
479 }
480
481 /*
482 * Control message
483 */
484 static int
ng_ccatm_rcvmsg(node_p node,item_p item,hook_p lasthook)485 ng_ccatm_rcvmsg(node_p node, item_p item, hook_p lasthook)
486 {
487 struct ng_mesg *resp = NULL;
488 struct ng_mesg *msg;
489 struct ccnode *priv = NG_NODE_PRIVATE(node);
490 int error = 0;
491
492 NGI_GET_MSG(item, msg);
493
494 switch (msg->header.typecookie) {
495
496 case NGM_CCATM_COOKIE:
497 switch (msg->header.cmd) {
498
499 case NGM_CCATM_DUMP:
500 if (priv->dump)
501 error = ng_ccatm_dump(node);
502 else
503 error = ENOTCONN;
504 break;
505
506 case NGM_CCATM_STOP:
507 {
508 struct ngm_ccatm_port *arg;
509
510 if (msg->header.arglen != sizeof(*arg)) {
511 error = EINVAL;
512 break;
513 }
514 arg = (struct ngm_ccatm_port *)msg->data;
515 error = cc_port_stop(priv->data, arg->port);
516 break;
517 }
518
519 case NGM_CCATM_START:
520 {
521 struct ngm_ccatm_port *arg;
522
523 if (msg->header.arglen != sizeof(*arg)) {
524 error = EINVAL;
525 break;
526 }
527 arg = (struct ngm_ccatm_port *)msg->data;
528 error = cc_port_start(priv->data, arg->port);
529 break;
530 }
531
532 case NGM_CCATM_GETSTATE:
533 {
534 struct ngm_ccatm_port *arg;
535 int state;
536
537 if (msg->header.arglen != sizeof(*arg)) {
538 error = EINVAL;
539 break;
540 }
541 arg = (struct ngm_ccatm_port *)msg->data;
542 error = cc_port_isrunning(priv->data, arg->port,
543 &state);
544 if (error == 0) {
545 NG_MKRESPONSE(resp, msg, sizeof(uint32_t),
546 M_NOWAIT);
547 if (resp == NULL) {
548 error = ENOMEM;
549 break;
550 }
551 *(uint32_t *)resp->data = state;
552 }
553 break;
554 }
555
556 case NGM_CCATM_GET_ADDRESSES:
557 {
558 struct ngm_ccatm_port *arg;
559
560 if (msg->header.arglen != sizeof(*arg)) {
561 error = EINVAL;
562 break;
563 }
564 arg = (struct ngm_ccatm_port *)msg->data;
565 error = ng_ccatm_get_addresses(node, arg->port, msg,
566 &resp);
567 break;
568 }
569
570 case NGM_CCATM_CLEAR:
571 {
572 struct ngm_ccatm_port *arg;
573
574 if (msg->header.arglen != sizeof(*arg)) {
575 error = EINVAL;
576 break;
577 }
578 arg = (struct ngm_ccatm_port *)msg->data;
579 error = cc_port_clear(priv->data, arg->port);
580 break;
581 }
582
583 case NGM_CCATM_ADDRESS_REGISTERED:
584 {
585 struct ngm_ccatm_addr_req *arg;
586
587 if (msg->header.arglen != sizeof(*arg)) {
588 error = EINVAL;
589 break;
590 }
591 arg = (struct ngm_ccatm_addr_req *)msg->data;
592 error = cc_addr_register(priv->data, arg->port,
593 &arg->addr);
594 break;
595 }
596
597 case NGM_CCATM_ADDRESS_UNREGISTERED:
598 {
599 struct ngm_ccatm_addr_req *arg;
600
601 if (msg->header.arglen != sizeof(*arg)) {
602 error = EINVAL;
603 break;
604 }
605 arg = (struct ngm_ccatm_addr_req *)msg->data;
606 error = cc_addr_unregister(priv->data, arg->port,
607 &arg->addr);
608 break;
609 }
610
611 case NGM_CCATM_GET_PORT_PARAM:
612 {
613 struct ngm_ccatm_port *arg;
614
615 if (msg->header.arglen != sizeof(*arg)) {
616 error = EINVAL;
617 break;
618 }
619 arg = (struct ngm_ccatm_port *)msg->data;
620 NG_MKRESPONSE(resp, msg, sizeof(struct atm_port_info),
621 M_NOWAIT);
622 if (resp == NULL) {
623 error = ENOMEM;
624 break;
625 }
626 error = cc_port_get_param(priv->data, arg->port,
627 (struct atm_port_info *)resp->data);
628 if (error != 0) {
629 free(resp, M_NETGRAPH_MSG);
630 resp = NULL;
631 }
632 break;
633 }
634
635 case NGM_CCATM_SET_PORT_PARAM:
636 {
637 struct atm_port_info *arg;
638
639 if (msg->header.arglen != sizeof(*arg)) {
640 error = EINVAL;
641 break;
642 }
643 arg = (struct atm_port_info *)msg->data;
644 error = cc_port_set_param(priv->data, arg);
645 break;
646 }
647
648 case NGM_CCATM_GET_PORTLIST:
649 {
650 struct ngm_ccatm_portlist *arg;
651 u_int n, *ports;
652
653 if (msg->header.arglen != 0) {
654 error = EINVAL;
655 break;
656 }
657 error = cc_port_getlist(priv->data, &n, &ports);
658 if (error != 0)
659 break;
660
661 NG_MKRESPONSE(resp, msg, sizeof(*arg) +
662 n * sizeof(arg->ports[0]), M_NOWAIT);
663 if (resp == NULL) {
664 free(ports, M_NG_CCATM);
665 error = ENOMEM;
666 break;
667 }
668 arg = (struct ngm_ccatm_portlist *)resp->data;
669
670 arg->nports = 0;
671 for (arg->nports = 0; arg->nports < n; arg->nports++)
672 arg->ports[arg->nports] = ports[arg->nports];
673 free(ports, M_NG_CCATM);
674 break;
675 }
676
677 case NGM_CCATM_SETLOG:
678 {
679 uint32_t log_level;
680
681 log_level = cc_get_log(priv->data);
682 if (msg->header.arglen != 0) {
683 if (msg->header.arglen != sizeof(log_level)) {
684 error = EINVAL;
685 break;
686 }
687 cc_set_log(priv->data, *(uint32_t *)msg->data);
688 }
689
690 NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
691 if (resp == NULL) {
692 error = ENOMEM;
693 if (msg->header.arglen != 0)
694 cc_set_log(priv->data, log_level);
695 break;
696 }
697 *(uint32_t *)resp->data = log_level;
698 break;
699 }
700
701 case NGM_CCATM_RESET:
702 if (msg->header.arglen != 0) {
703 error = EINVAL;
704 break;
705 }
706
707 if (priv->hook_cnt != 0) {
708 error = EBUSY;
709 break;
710 }
711 cc_reset(priv->data);
712 break;
713
714 case NGM_CCATM_GET_EXSTAT:
715 {
716 struct atm_exstatus s;
717 struct atm_exstatus_ep *eps;
718 struct atm_exstatus_port *ports;
719 struct atm_exstatus_conn *conns;
720 struct atm_exstatus_party *parties;
721 size_t offs;
722
723 if (msg->header.arglen != 0) {
724 error = EINVAL;
725 break;
726 }
727 error = cc_get_extended_status(priv->data,
728 &s, &eps, &ports, &conns, &parties);
729 if (error != 0)
730 break;
731
732 offs = sizeof(s) + s.neps * sizeof(*eps) +
733 s.nports * sizeof(*ports) +
734 s.nconns * sizeof(*conns) +
735 s.nparties * sizeof(*parties);
736
737 NG_MKRESPONSE(resp, msg, offs, M_NOWAIT);
738 if (resp == NULL) {
739 error = ENOMEM;
740 break;
741 }
742
743 memcpy(resp->data, &s, sizeof(s));
744 offs = sizeof(s);
745
746 memcpy(resp->data + offs, eps,
747 sizeof(*eps) * s.neps);
748 offs += sizeof(*eps) * s.neps;
749
750 memcpy(resp->data + offs, ports,
751 sizeof(*ports) * s.nports);
752 offs += sizeof(*ports) * s.nports;
753
754 memcpy(resp->data + offs, conns,
755 sizeof(*conns) * s.nconns);
756 offs += sizeof(*conns) * s.nconns;
757
758 memcpy(resp->data + offs, parties,
759 sizeof(*parties) * s.nparties);
760 offs += sizeof(*parties) * s.nparties;
761
762 free(eps, M_NG_CCATM);
763 free(ports, M_NG_CCATM);
764 free(conns, M_NG_CCATM);
765 free(parties, M_NG_CCATM);
766 break;
767 }
768
769 default:
770 error = EINVAL;
771 break;
772
773 }
774 break;
775
776 default:
777 error = EINVAL;
778 break;
779
780 }
781
782 NG_RESPOND_MSG(error, node, item, resp);
783 NG_FREE_MSG(msg);
784 return (error);
785 }
786
787 /************************************************************
788 *
789 * New hook arrival
790 */
791 static int
ng_ccatm_newhook(node_p node,hook_p hook,const char * name)792 ng_ccatm_newhook(node_p node, hook_p hook, const char *name)
793 {
794 struct ccnode *priv = NG_NODE_PRIVATE(node);
795 struct ccport *port;
796 struct ccuser *user;
797 struct cchook *hd;
798 u_long lport;
799 char *end;
800
801 if (strncmp(name, "uni", 3) == 0) {
802 /*
803 * This is a UNI hook. Should be a new port.
804 */
805 if (name[3] == '\0')
806 return (EINVAL);
807 lport = strtoul(name + 3, &end, 10);
808 if (*end != '\0' || lport == 0 || lport > 0xffffffff)
809 return (EINVAL);
810
811 hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
812 if (hd == NULL)
813 return (ENOMEM);
814 hd->is_uni = 1;
815 hd->node = priv;
816 hd->hook = hook;
817
818 port = cc_port_create(priv->data, hd, (u_int)lport);
819 if (port == NULL) {
820 free(hd, M_NG_CCATM);
821 return (ENOMEM);
822 }
823 hd->inst = port;
824
825 NG_HOOK_SET_PRIVATE(hook, hd);
826 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvuni);
827 NG_HOOK_FORCE_QUEUE(hook);
828
829 priv->hook_cnt++;
830
831 return (0);
832 }
833
834 if (strcmp(name, "dump") == 0) {
835 priv->dump = hook;
836 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvdump);
837 return (0);
838 }
839
840 if (strcmp(name, "manage") == 0) {
841 priv->manage = hook;
842 NG_HOOK_SET_RCVDATA(hook, ng_ccatm_rcvmanage);
843 return (0);
844 }
845
846 /*
847 * User hook
848 */
849 hd = malloc(sizeof(*hd), M_NG_CCATM, M_NOWAIT);
850 if (hd == NULL)
851 return (ENOMEM);
852 hd->is_uni = 0;
853 hd->node = priv;
854 hd->hook = hook;
855
856 user = cc_user_create(priv->data, hd, NG_HOOK_NAME(hook));
857 if (user == NULL) {
858 free(hd, M_NG_CCATM);
859 return (ENOMEM);
860 }
861
862 hd->inst = user;
863 NG_HOOK_SET_PRIVATE(hook, hd);
864 NG_HOOK_FORCE_QUEUE(hook);
865
866 priv->hook_cnt++;
867
868 return (0);
869 }
870
871 /*
872 * Disconnect a hook
873 */
874 static int
ng_ccatm_disconnect(hook_p hook)875 ng_ccatm_disconnect(hook_p hook)
876 {
877 node_p node = NG_HOOK_NODE(hook);
878 struct ccnode *priv = NG_NODE_PRIVATE(node);
879 struct cchook *hd = NG_HOOK_PRIVATE(hook);
880 struct ccdata *cc;
881
882 if (hook == priv->dump) {
883 priv->dump = NULL;
884
885 } else if (hook == priv->manage) {
886 priv->manage = NULL;
887 cc_unmanage(priv->data);
888
889 } else {
890 if (hd->is_uni)
891 cc_port_destroy(hd->inst, 0);
892 else
893 cc_user_destroy(hd->inst);
894
895 cc = hd->node->data;
896
897 free(hd, M_NG_CCATM);
898 NG_HOOK_SET_PRIVATE(hook, NULL);
899
900 priv->hook_cnt--;
901
902 cc_work(cc);
903 }
904
905 /*
906 * When the number of hooks drops to zero, delete the node.
907 */
908 if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node))
909 ng_rmnode_self(node);
910
911 return (0);
912 }
913
914 /************************************************************
915 *
916 * Receive data from user hook
917 */
918 static int
ng_ccatm_rcvdata(hook_p hook,item_p item)919 ng_ccatm_rcvdata(hook_p hook, item_p item)
920 {
921 struct cchook *hd = NG_HOOK_PRIVATE(hook);
922 struct uni_msg *msg;
923 struct mbuf *m;
924 struct ccatm_op op;
925 int err;
926
927 NGI_GET_M(item, m);
928 NG_FREE_ITEM(item);
929
930 if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
931 m_freem(m);
932 return (err);
933 }
934 m_freem(m);
935
936 if (uni_msg_len(msg) < sizeof(op)) {
937 printf("%s: packet too short\n", __func__);
938 uni_msg_destroy(msg);
939 return (EINVAL);
940 }
941
942 bcopy(msg->b_rptr, &op, sizeof(op));
943 msg->b_rptr += sizeof(op);
944
945 err = cc_user_signal(hd->inst, op.op, msg);
946 cc_work(hd->node->data);
947 return (err);
948 }
949
950 /*
951 * Pack a header and a data area into an mbuf chain
952 */
953 static struct mbuf *
pack_buf(void * h,size_t hlen,void * t,size_t tlen)954 pack_buf(void *h, size_t hlen, void *t, size_t tlen)
955 {
956 struct mbuf *m, *m0, *last;
957 u_char *buf = (u_char *)t;
958 size_t n;
959
960 /* header should fit into a normal mbuf */
961 MGETHDR(m0, M_NOWAIT, MT_DATA);
962 if (m0 == NULL)
963 return NULL;
964
965 KASSERT(hlen <= MHLEN, ("hlen > MHLEN"));
966
967 bcopy(h, m0->m_data, hlen);
968 m0->m_len = hlen;
969 m0->m_pkthdr.len = hlen;
970
971 last = m0;
972 while ((n = tlen) != 0) {
973 if (n > MLEN) {
974 m = m_getcl(M_NOWAIT, MT_DATA, 0);
975 if (n > MCLBYTES)
976 n = MCLBYTES;
977 } else
978 MGET(m, M_NOWAIT, MT_DATA);
979
980 if(m == NULL)
981 goto drop;
982
983 last->m_next = m;
984 last = m;
985
986 bcopy(buf, m->m_data, n);
987 buf += n;
988 tlen -= n;
989 m->m_len = n;
990 m0->m_pkthdr.len += n;
991 }
992
993 return (m0);
994
995 drop:
996 m_freem(m0);
997 return NULL;
998 }
999
1000 /*
1001 * Send an indication to the user.
1002 */
1003 static void
ng_ccatm_send_user(struct ccuser * user,void * uarg,u_int op,void * val,size_t len)1004 ng_ccatm_send_user(struct ccuser *user, void *uarg, u_int op,
1005 void *val, size_t len)
1006 {
1007 struct cchook *hd = uarg;
1008 struct mbuf *m;
1009 struct ccatm_op h;
1010 int error;
1011
1012 h.op = op;
1013 m = pack_buf(&h, sizeof(h), val, len);
1014 if (m == NULL)
1015 return;
1016
1017 NG_SEND_DATA_ONLY(error, hd->hook, m);
1018 if (error != 0)
1019 printf("%s: error=%d\n", __func__, error);
1020 }
1021
1022 /*
1023 * Send a response to the user.
1024 */
1025 static void
ng_ccatm_respond_user(struct ccuser * user,void * uarg,int err,u_int data,void * val,size_t len)1026 ng_ccatm_respond_user(struct ccuser *user, void *uarg, int err, u_int data,
1027 void *val, size_t len)
1028 {
1029 struct cchook *hd = uarg;
1030 struct mbuf *m;
1031 struct {
1032 struct ccatm_op op;
1033 struct atm_resp resp;
1034 } resp;
1035 int error;
1036
1037 resp.op.op = ATMOP_RESP;
1038 resp.resp.resp = err;
1039 resp.resp.data = data;
1040 m = pack_buf(&resp, sizeof(resp), val, len);
1041 if (m == NULL)
1042 return;
1043
1044 NG_SEND_DATA_ONLY(error, hd->hook, m);
1045 if (error != 0)
1046 printf("%s: error=%d\n", __func__, error);
1047 }
1048
1049 /*
1050 * Receive data from UNI.
1051 */
1052 static int
ng_ccatm_rcvuni(hook_p hook,item_p item)1053 ng_ccatm_rcvuni(hook_p hook, item_p item)
1054 {
1055 struct cchook *hd = NG_HOOK_PRIVATE(hook);
1056 struct uni_msg *msg;
1057 struct uni_arg arg;
1058 struct mbuf *m;
1059 int err;
1060
1061 NGI_GET_M(item, m);
1062 NG_FREE_ITEM(item);
1063
1064 if ((err = uni_msg_unpack_mbuf(m, &msg)) != 0) {
1065 m_freem(m);
1066 return (err);
1067 }
1068 m_freem(m);
1069
1070 if (uni_msg_len(msg) < sizeof(arg)) {
1071 printf("%s: packet too short\n", __func__);
1072 uni_msg_destroy(msg);
1073 return (EINVAL);
1074 }
1075
1076 bcopy(msg->b_rptr, &arg, sizeof(arg));
1077 msg->b_rptr += sizeof(arg);
1078
1079 if (arg.sig == UNIAPI_ERROR) {
1080 if (uni_msg_len(msg) != sizeof(struct uniapi_error)) {
1081 printf("%s: bad UNIAPI_ERROR size %zu\n", __func__,
1082 uni_msg_len(msg));
1083 uni_msg_destroy(msg);
1084 return (EINVAL);
1085 }
1086 err = cc_uni_response(hd->inst, arg.cookie,
1087 ((struct uniapi_error *)msg->b_rptr)->reason,
1088 ((struct uniapi_error *)msg->b_rptr)->state);
1089 uni_msg_destroy(msg);
1090 } else
1091 err = cc_uni_signal(hd->inst, arg.cookie, arg.sig, msg);
1092
1093 cc_work(hd->node->data);
1094 return (err);
1095 }
1096
1097 /*
1098 * Uarg is the port's uarg.
1099 */
1100 static void
ng_ccatm_send_uni(struct ccconn * conn,void * uarg,u_int op,u_int cookie,struct uni_msg * msg)1101 ng_ccatm_send_uni(struct ccconn *conn, void *uarg, u_int op, u_int cookie,
1102 struct uni_msg *msg)
1103 {
1104 struct cchook *hd = uarg;
1105 struct uni_arg arg;
1106 struct mbuf *m;
1107 int error;
1108
1109 arg.sig = op;
1110 arg.cookie = cookie;
1111
1112 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1113 uni_msg_destroy(msg);
1114 if (m == NULL)
1115 return;
1116
1117 NG_SEND_DATA_ONLY(error, hd->hook, m);
1118 if (error != 0)
1119 printf("%s: error=%d\n", __func__, error);
1120 }
1121
1122 /*
1123 * Send a global message to the UNI
1124 */
1125 static void
ng_ccatm_send_uni_glob(struct ccport * port,void * uarg,u_int op,u_int cookie,struct uni_msg * msg)1126 ng_ccatm_send_uni_glob(struct ccport *port, void *uarg, u_int op, u_int cookie,
1127 struct uni_msg *msg)
1128 {
1129 struct cchook *hd = uarg;
1130 struct uni_arg arg;
1131 struct mbuf *m;
1132 int error;
1133
1134 arg.sig = op;
1135 arg.cookie = cookie;
1136
1137 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
1138 if (msg != NULL)
1139 uni_msg_destroy(msg);
1140 if (m == NULL)
1141 return;
1142
1143 NG_SEND_DATA_ONLY(error, hd->hook, m);
1144 if (error != 0)
1145 printf("%s: error=%d\n", __func__, error);
1146 }
1147 /*
1148 * Receive from ILMID
1149 */
1150 static int
ng_ccatm_rcvmanage(hook_p hook,item_p item)1151 ng_ccatm_rcvmanage(hook_p hook, item_p item)
1152 {
1153 NG_FREE_ITEM(item);
1154 return (0);
1155 }
1156
1157 static int
ng_ccatm_rcvdump(hook_p hook,item_p item)1158 ng_ccatm_rcvdump(hook_p hook, item_p item)
1159 {
1160 NG_FREE_ITEM(item);
1161 return (0);
1162 }
1163
1164 static void
ng_ccatm_log(const char * fmt,...)1165 ng_ccatm_log(const char *fmt, ...)
1166 {
1167 va_list ap;
1168
1169 va_start(ap, fmt);
1170 vprintf(fmt, ap);
1171 printf("\n");
1172 va_end(ap);
1173 }
1174
1175 /*
1176 * Loading and unloading of node type
1177 */
1178 static int
ng_ccatm_mod_event(module_t mod,int event,void * data)1179 ng_ccatm_mod_event(module_t mod, int event, void *data)
1180 {
1181 int error = 0;
1182
1183 switch (event) {
1184
1185 case MOD_LOAD:
1186 break;
1187
1188 case MOD_UNLOAD:
1189 break;
1190
1191 default:
1192 error = EOPNOTSUPP;
1193 break;
1194 }
1195 return (error);
1196 }
1197