ng_ccatm.c revision 302408
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: stable/11/sys/netgraph/atm/ccatm/ng_ccatm.c 298075 2016-04-15 17:30:33Z pfg $ 34 * 35 * ATM call control and API 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: stable/11/sys/netgraph/atm/ccatm/ng_ccatm.c 298075 2016-04-15 17:30:33Z pfg $"); 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 65MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1); 66 67MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node"); 68 69/* 70 * Command structure parsing 71 */ 72 73/* ESI */ 74static const struct ng_parse_fixedarray_info ng_ccatm_esi_type_info = 75 NGM_CCATM_ESI_INFO; 76static 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 */ 82static const struct ng_parse_struct_field ng_ccatm_atm_port_type_info[] = 83 NGM_CCATM_ATM_PORT_INFO; 84static 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 */ 90static const struct ng_parse_struct_field ng_ccatm_port_type_info[] = 91 NGM_CCATM_PORT_INFO; 92static 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 */ 98static const struct ng_parse_fixedarray_info ng_ccatm_addr_array_type_info = 99 NGM_CCATM_ADDR_ARRAY_INFO; 100static 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 */ 106static const struct ng_parse_struct_field ng_ccatm_uni_addr_type_info[] = 107 NGM_CCATM_UNI_ADDR_INFO; 108static 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 */ 114static const struct ng_parse_struct_field ng_ccatm_addr_req_type_info[] = 115 NGM_CCATM_ADDR_REQ_INFO; 116static 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 */ 122static int 123ng_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} 132static const struct ng_parse_array_info ng_ccatm_addr_req_array_type_info = 133 NGM_CCATM_ADDR_REQ_ARRAY_INFO; 134static 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 */ 140static const struct ng_parse_struct_field ng_ccatm_get_addresses_type_info[] = 141 NGM_CCATM_GET_ADDRESSES_INFO; 142static 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 */ 148static int 149ng_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} 158static const struct ng_parse_array_info ng_ccatm_port_array_type_info = 159 NGM_CCATM_PORT_ARRAY_INFO; 160static 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 */ 166static const struct ng_parse_struct_field ng_ccatm_portlist_type_info[] = 167 NGM_CCATM_PORTLIST_INFO; 168static 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 */ 176static 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 */ 274static ng_constructor_t ng_ccatm_constructor; 275static ng_rcvmsg_t ng_ccatm_rcvmsg; 276static ng_shutdown_t ng_ccatm_shutdown; 277static ng_newhook_t ng_ccatm_newhook; 278static ng_rcvdata_t ng_ccatm_rcvdata; 279static ng_disconnect_t ng_ccatm_disconnect; 280static int ng_ccatm_mod_event(module_t, int, void *); 281 282static 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}; 294NETGRAPH_INIT(ccatm, &ng_ccatm_typestruct); 295 296static ng_rcvdata_t ng_ccatm_rcvuni; 297static ng_rcvdata_t ng_ccatm_rcvdump; 298static ng_rcvdata_t ng_ccatm_rcvmanage; 299 300/* 301 * Private node data. 302 */ 303struct 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 */ 318struct 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 325static void ng_ccatm_send_user(struct ccuser *, void *, u_int, void *, size_t); 326static void ng_ccatm_respond_user(struct ccuser *, void *, int, u_int, 327 void *, size_t); 328static void ng_ccatm_send_uni(struct ccconn *, void *, u_int, u_int, 329 struct uni_msg *); 330static void ng_ccatm_send_uni_glob(struct ccport *, void *, u_int, u_int, 331 struct uni_msg *); 332static void ng_ccatm_log(const char *, ...) __printflike(1, 2); 333 334static 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 */ 346static int 347ng_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 */ 371static int 372ng_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 */ 390static int 391ng_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 */ 430static int 431send_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 */ 461static int 462ng_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 */ 484static int 485ng_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 */ 791static int 792ng_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 */ 874static int 875ng_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 */ 918static int 919ng_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 */ 953static struct mbuf * 954pack_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 */ 1003static void 1004ng_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 */ 1025static void 1026ng_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 */ 1052static int 1053ng_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 */ 1100static void 1101ng_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 */ 1125static void 1126ng_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 */ 1150static int 1151ng_ccatm_rcvmanage(hook_p hook, item_p item) 1152{ 1153 NG_FREE_ITEM(item); 1154 return (0); 1155} 1156 1157static int 1158ng_ccatm_rcvdump(hook_p hook, item_p item) 1159{ 1160 NG_FREE_ITEM(item); 1161 return (0); 1162} 1163 1164static void 1165ng_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 */ 1178static int 1179ng_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