1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2001-2003 5 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 6 * All rights reserved. 7 * 8 * Author: Hartmut Brandt <harti@freebsd.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * Netgraph module for ATM-Forum UNI 4.0 signalling 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 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/syslog.h> 44#include <sys/socket.h> 45#include <sys/socketvar.h> 46#include <sys/callout.h> 47#include <sys/sbuf.h> 48#include <machine/stdarg.h> 49 50#include <netgraph/ng_message.h> 51#include <netgraph/netgraph.h> 52#include <netgraph/ng_parse.h> 53#include <netnatm/unimsg.h> 54#include <netnatm/msg/unistruct.h> 55#include <netgraph/atm/ngatmbase.h> 56#include <netnatm/saal/sscopdef.h> 57#include <netnatm/saal/sscfudef.h> 58#include <netgraph/atm/uni/ng_uni_cust.h> 59#include <netnatm/sig/uni.h> 60#include <netnatm/sig/unisig.h> 61#include <netgraph/atm/ng_sscop.h> 62#include <netgraph/atm/ng_sscfu.h> 63#include <netgraph/atm/ng_uni.h> 64 65static MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node"); 66static MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data"); 67 68MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1); 69 70/* 71 * Private node data 72 */ 73struct priv { 74 hook_p upper; 75 hook_p lower; 76 struct uni *uni; 77 int enabled; 78}; 79 80/* UNI CONFIG MASK */ 81static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] = 82 NGM_UNI_CONFIG_MASK_INFO; 83static const struct ng_parse_type ng_uni_config_mask_type = { 84 &ng_parse_struct_type, 85 ng_uni_config_mask_type_info 86}; 87 88/* UNI_CONFIG */ 89static const struct ng_parse_struct_field ng_uni_config_type_info[] = 90 NGM_UNI_CONFIG_INFO; 91static const struct ng_parse_type ng_uni_config_type = { 92 &ng_parse_struct_type, 93 ng_uni_config_type_info 94}; 95 96/* SET CONFIG */ 97static const struct ng_parse_struct_field ng_uni_set_config_type_info[] = 98 NGM_UNI_SET_CONFIG_INFO; 99static const struct ng_parse_type ng_uni_set_config_type = { 100 &ng_parse_struct_type, 101 ng_uni_set_config_type_info 102}; 103 104/* 105 * Parse DEBUG 106 */ 107static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info = 108 NGM_UNI_DEBUGLEVEL_INFO; 109static const struct ng_parse_type ng_uni_debuglevel_type = { 110 &ng_parse_fixedarray_type, 111 &ng_uni_debuglevel_type_info 112}; 113static const struct ng_parse_struct_field ng_uni_debug_type_info[] = 114 NGM_UNI_DEBUG_INFO; 115static const struct ng_parse_type ng_uni_debug_type = { 116 &ng_parse_struct_type, 117 ng_uni_debug_type_info 118}; 119 120/* 121 * Command list 122 */ 123static const struct ng_cmdlist ng_uni_cmdlist[] = { 124 { 125 NGM_UNI_COOKIE, 126 NGM_UNI_GETDEBUG, 127 "getdebug", 128 NULL, 129 &ng_uni_debug_type 130 }, 131 { 132 NGM_UNI_COOKIE, 133 NGM_UNI_SETDEBUG, 134 "setdebug", 135 &ng_uni_debug_type, 136 NULL 137 }, 138 { 139 NGM_UNI_COOKIE, 140 NGM_UNI_GET_CONFIG, 141 "get_config", 142 NULL, 143 &ng_uni_config_type 144 }, 145 { 146 NGM_UNI_COOKIE, 147 NGM_UNI_SET_CONFIG, 148 "set_config", 149 &ng_uni_set_config_type, 150 &ng_uni_config_mask_type, 151 }, 152 { 153 NGM_UNI_COOKIE, 154 NGM_UNI_ENABLE, 155 "enable", 156 NULL, 157 NULL, 158 }, 159 { 160 NGM_UNI_COOKIE, 161 NGM_UNI_DISABLE, 162 "disable", 163 NULL, 164 NULL, 165 }, 166 { 167 NGM_UNI_COOKIE, 168 NGM_UNI_GETSTATE, 169 "getstate", 170 NULL, 171 &ng_parse_uint32_type 172 }, 173 { 0 } 174}; 175 176/* 177 * Netgraph module data 178 */ 179static ng_constructor_t ng_uni_constructor; 180static ng_shutdown_t ng_uni_shutdown; 181static ng_rcvmsg_t ng_uni_rcvmsg; 182static ng_newhook_t ng_uni_newhook; 183static ng_disconnect_t ng_uni_disconnect; 184static ng_rcvdata_t ng_uni_rcvlower; 185static ng_rcvdata_t ng_uni_rcvupper; 186 187static int ng_uni_mod_event(module_t, int, void *); 188 189static struct ng_type ng_uni_typestruct = { 190 .version = NG_ABI_VERSION, 191 .name = NG_UNI_NODE_TYPE, 192 .mod_event = ng_uni_mod_event, 193 .constructor = ng_uni_constructor, 194 .rcvmsg = ng_uni_rcvmsg, 195 .shutdown = ng_uni_shutdown, 196 .newhook = ng_uni_newhook, 197 .rcvdata = ng_uni_rcvlower, 198 .disconnect = ng_uni_disconnect, 199 .cmdlist = ng_uni_cmdlist, 200}; 201NETGRAPH_INIT(uni, &ng_uni_typestruct); 202 203static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t, 204 struct uni_msg *); 205static void uni_saal_output(struct uni *, void *, enum saal_sig, 206 struct uni_msg *); 207static void uni_verbose(struct uni *, void *, u_int, const char *, ...) 208 __printflike(4, 5); 209static void uni_do_status(struct uni *, void *, void *, const char *, ...) 210 __printflike(4, 5); 211 212static const struct uni_funcs uni_funcs = { 213 uni_uni_output, 214 uni_saal_output, 215 uni_verbose, 216 uni_do_status 217}; 218 219/************************************************************/ 220/* 221 * NODE MANAGEMENT 222 */ 223static int 224ng_uni_constructor(node_p node) 225{ 226 struct priv *priv; 227 228 priv = malloc(sizeof(*priv), M_NG_UNI, M_WAITOK | M_ZERO); 229 230 if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) { 231 free(priv, M_NG_UNI); 232 return (ENOMEM); 233 } 234 235 NG_NODE_SET_PRIVATE(node, priv); 236 NG_NODE_FORCE_WRITER(node); 237 238 return (0); 239} 240 241static int 242ng_uni_shutdown(node_p node) 243{ 244 struct priv *priv = NG_NODE_PRIVATE(node); 245 246 uni_destroy(priv->uni); 247 248 free(priv, M_NG_UNI); 249 NG_NODE_SET_PRIVATE(node, NULL); 250 251 NG_NODE_UNREF(node); 252 253 return (0); 254} 255 256/************************************************************/ 257/* 258 * CONTROL MESSAGES 259 */ 260static void 261uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...) 262{ 263 va_list ap; 264 265 va_start(ap, fmt); 266 sbuf_printf(sbuf, fmt, ap); 267 va_end(ap); 268} 269 270static int 271text_status(node_p node, struct priv *priv, char *buf, u_int len) 272{ 273 struct sbuf sbuf; 274 u_int f; 275 276 sbuf_new(&sbuf, buf, len, 0); 277 278 if (priv->lower != NULL) 279 sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n", 280 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), 281 NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); 282 else 283 sbuf_printf(&sbuf, "lower hook: <not connected>\n"); 284 285 if (priv->upper != NULL) 286 sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n", 287 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), 288 NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); 289 else 290 sbuf_printf(&sbuf, "upper hook: <not connected>\n"); 291 292 sbuf_printf(&sbuf, "debugging:"); 293 for (f = 0; f < UNI_MAXFACILITY; f++) 294 if (uni_get_debug(priv->uni, f) != 0) 295 sbuf_printf(&sbuf, " %s=%u", uni_facname(f), 296 uni_get_debug(priv->uni, f)); 297 sbuf_printf(&sbuf, "\n"); 298 299 if (priv->uni) 300 uni_status(priv->uni, &sbuf); 301 302 sbuf_finish(&sbuf); 303 return (sbuf_len(&sbuf)); 304} 305 306static int 307ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook) 308{ 309 struct priv *priv = NG_NODE_PRIVATE(node); 310 struct ng_mesg *resp = NULL; 311 struct ng_mesg *msg; 312 int error = 0; 313 u_int i; 314 315 NGI_GET_MSG(item, msg); 316 317 switch (msg->header.typecookie) { 318 case NGM_GENERIC_COOKIE: 319 switch (msg->header.cmd) { 320 case NGM_TEXT_STATUS: 321 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 322 if (resp == NULL) { 323 error = ENOMEM; 324 break; 325 } 326 327 resp->header.arglen = text_status(node, priv, 328 (char *)resp->data, resp->header.arglen) + 1; 329 break; 330 331 default: 332 error = EINVAL; 333 break; 334 } 335 break; 336 337 case NGM_UNI_COOKIE: 338 switch (msg->header.cmd) { 339 case NGM_UNI_SETDEBUG: 340 { 341 struct ngm_uni_debug *arg; 342 343 if (msg->header.arglen > sizeof(*arg)) { 344 error = EINVAL; 345 break; 346 } 347 arg = (struct ngm_uni_debug *)msg->data; 348 for (i = 0; i < UNI_MAXFACILITY; i++) 349 uni_set_debug(priv->uni, i, arg->level[i]); 350 break; 351 } 352 353 case NGM_UNI_GETDEBUG: 354 { 355 struct ngm_uni_debug *arg; 356 357 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 358 if(resp == NULL) { 359 error = ENOMEM; 360 break; 361 } 362 arg = (struct ngm_uni_debug *)resp->data; 363 for (i = 0; i < UNI_MAXFACILITY; i++) 364 arg->level[i] = uni_get_debug(priv->uni, i); 365 break; 366 } 367 368 case NGM_UNI_GET_CONFIG: 369 { 370 struct uni_config *config; 371 372 if (msg->header.arglen != 0) { 373 error = EINVAL; 374 break; 375 } 376 NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT); 377 if (resp == NULL) { 378 error = ENOMEM; 379 break; 380 } 381 config = (struct uni_config *)resp->data; 382 uni_get_config(priv->uni, config); 383 384 break; 385 } 386 387 case NGM_UNI_SET_CONFIG: 388 { 389 struct ngm_uni_set_config *arg; 390 struct ngm_uni_config_mask *mask; 391 392 if (msg->header.arglen != sizeof(*arg)) { 393 error = EINVAL; 394 break; 395 } 396 arg = (struct ngm_uni_set_config *)msg->data; 397 398 NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT); 399 if (resp == NULL) { 400 error = ENOMEM; 401 break; 402 } 403 mask = (struct ngm_uni_config_mask *)resp->data; 404 405 *mask = arg->mask; 406 407 uni_set_config(priv->uni, &arg->config, 408 &mask->mask, &mask->popt_mask, &mask->option_mask); 409 410 break; 411 } 412 413 case NGM_UNI_ENABLE: 414 if (msg->header.arglen != 0) { 415 error = EINVAL; 416 break; 417 } 418 if (priv->enabled) { 419 error = EISCONN; 420 break; 421 } 422 priv->enabled = 1; 423 break; 424 425 case NGM_UNI_DISABLE: 426 if (msg->header.arglen != 0) { 427 error = EINVAL; 428 break; 429 } 430 if (!priv->enabled) { 431 error = ENOTCONN; 432 break; 433 } 434 priv->enabled = 0; 435 uni_reset(priv->uni); 436 break; 437 438 case NGM_UNI_GETSTATE: 439 if (msg->header.arglen != 0) { 440 error = EINVAL; 441 break; 442 } 443 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 444 if(resp == NULL) { 445 error = ENOMEM; 446 break; 447 } 448 *(u_int32_t *)resp->data = 449 priv->enabled ? (uni_getcustate(priv->uni) + 1) 450 : 0; 451 break; 452 453 default: 454 error = EINVAL; 455 break; 456 } 457 break; 458 459 default: 460 error = EINVAL; 461 break; 462 } 463 464 NG_RESPOND_MSG(error, node, item, resp); 465 NG_FREE_MSG(msg); 466 return (error); 467} 468 469/************************************************************/ 470/* 471 * HOOK MANAGEMENT 472 */ 473static int 474ng_uni_newhook(node_p node, hook_p hook, const char *name) 475{ 476 struct priv *priv = NG_NODE_PRIVATE(node); 477 478 if (strcmp(name, "lower") == 0) { 479 priv->lower = hook; 480 } else if(strcmp(name, "upper") == 0) { 481 priv->upper = hook; 482 NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper); 483 } else 484 return EINVAL; 485 486 return 0; 487} 488 489static int 490ng_uni_disconnect(hook_p hook) 491{ 492 node_p node = NG_HOOK_NODE(hook); 493 struct priv *priv = NG_NODE_PRIVATE(node); 494 495 if(hook == priv->lower) 496 priv->lower = NULL; 497 else if(hook == priv->upper) 498 priv->upper = NULL; 499 else 500 printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook)); 501 502 if (NG_NODE_NUMHOOKS(node) == 0) { 503 if (NG_NODE_IS_VALID(node)) 504 ng_rmnode_self(node); 505 } 506 507 return (0); 508} 509 510/************************************************************/ 511/* 512 * DATA 513 */ 514/* 515 * Receive signal from USER. 516 * 517 * Repackage the data into one large buffer. 518 */ 519static int 520ng_uni_rcvupper(hook_p hook, item_p item) 521{ 522 node_p node = NG_HOOK_NODE(hook); 523 struct priv *priv = NG_NODE_PRIVATE(node); 524 struct mbuf *m; 525 struct uni_arg arg; 526 struct uni_msg *msg; 527 int error; 528 529 if (!priv->enabled) { 530 NG_FREE_ITEM(item); 531 return (ENOTCONN); 532 } 533 534 NGI_GET_M(item, m); 535 NG_FREE_ITEM(item); 536 537 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { 538 m_freem(m); 539 return (error); 540 } 541 m_freem(m); 542 543 if (uni_msg_len(msg) < sizeof(arg)) { 544 printf("%s: packet too short\n", __func__); 545 uni_msg_destroy(msg); 546 return (EINVAL); 547 } 548 549 bcopy(msg->b_rptr, &arg, sizeof(arg)); 550 msg->b_rptr += sizeof(arg); 551 552 if (arg.sig >= UNIAPI_MAXSIG) { 553 printf("%s: bogus signal\n", __func__); 554 uni_msg_destroy(msg); 555 return (EINVAL); 556 } 557 uni_uni_input(priv->uni, arg.sig, arg.cookie, msg); 558 uni_work(priv->uni); 559 560 return (0); 561} 562 563/* 564 * Upper layer signal from UNI 565 */ 566static void 567uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie, 568 struct uni_msg *msg) 569{ 570 node_p node = (node_p)varg; 571 struct priv *priv = NG_NODE_PRIVATE(node); 572 struct mbuf *m; 573 struct uni_arg arg; 574 int error; 575 576 if (priv->upper == NULL) { 577 if (msg != NULL) 578 uni_msg_destroy(msg); 579 return; 580 } 581 arg.sig = sig; 582 arg.cookie = cookie; 583 584 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); 585 if (msg != NULL) 586 uni_msg_destroy(msg); 587 if (m == NULL) 588 return; 589 590 NG_SEND_DATA_ONLY(error, priv->upper, m); 591} 592 593static void 594dump_uni_msg(struct uni_msg *msg) 595{ 596 u_int pos; 597 598 for (pos = 0; pos < uni_msg_len(msg); pos++) { 599 if (pos % 16 == 0) 600 printf("%06o ", pos); 601 if (pos % 16 == 8) 602 printf(" "); 603 printf(" %02x", msg->b_rptr[pos]); 604 if (pos % 16 == 15) 605 printf("\n"); 606 } 607 if (pos % 16 != 0) 608 printf("\n"); 609} 610 611/* 612 * Dump a SAAL signal in either direction 613 */ 614static void 615dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to) 616{ 617 struct priv *priv = NG_NODE_PRIVATE(node); 618 619 printf("signal %s SAAL: ", to ? "to" : "from"); 620 621 switch (sig) { 622#define D(S) case S: printf("%s", #S); break 623 624 D(SAAL_ESTABLISH_request); 625 D(SAAL_ESTABLISH_indication); 626 D(SAAL_ESTABLISH_confirm); 627 D(SAAL_RELEASE_request); 628 D(SAAL_RELEASE_confirm); 629 D(SAAL_RELEASE_indication); 630 D(SAAL_DATA_request); 631 D(SAAL_DATA_indication); 632 D(SAAL_UDATA_request); 633 D(SAAL_UDATA_indication); 634 635#undef D 636 default: 637 printf("sig=%d", sig); break; 638 } 639 if (msg != NULL) { 640 printf(" data=%zu\n", uni_msg_len(msg)); 641 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1) 642 dump_uni_msg(msg); 643 } else 644 printf("\n"); 645} 646 647/* 648 * Receive signal from SSCOP. 649 * 650 * If this is a data signal, repackage the data into one large buffer. 651 * UNI shouldn't be the bottleneck in a system and this greatly simplifies 652 * parsing in UNI. 653 */ 654static int 655ng_uni_rcvlower(hook_p hook __unused, item_p item) 656{ 657 node_p node = NG_HOOK_NODE(hook); 658 struct priv *priv = NG_NODE_PRIVATE(node); 659 struct mbuf *m; 660 struct sscfu_arg arg; 661 struct uni_msg *msg; 662 int error; 663 664 if (!priv->enabled) { 665 NG_FREE_ITEM(item); 666 return (ENOTCONN); 667 } 668 669 NGI_GET_M(item, m); 670 NG_FREE_ITEM(item); 671 672 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { 673 m_freem(m); 674 return (error); 675 } 676 m_freem(m); 677 678 if (uni_msg_len(msg) < sizeof(arg)) { 679 uni_msg_destroy(msg); 680 printf("%s: packet too short\n", __func__); 681 return (EINVAL); 682 } 683 bcopy(msg->b_rptr, &arg, sizeof(arg)); 684 msg->b_rptr += sizeof(arg); 685 686 if (arg.sig > SAAL_UDATA_indication) { 687 uni_msg_destroy(msg); 688 printf("%s: bogus signal\n", __func__); 689 return (EINVAL); 690 } 691 692 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) 693 dump_saal_signal(node, arg.sig, msg, 0); 694 695 uni_saal_input(priv->uni, arg.sig, msg); 696 uni_work(priv->uni); 697 698 return (0); 699} 700 701/* 702 * Send signal to sscop. 703 * Pack the message into an mbuf chain. 704 */ 705static void 706uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg) 707{ 708 node_p node = (node_p)varg; 709 struct priv *priv = NG_NODE_PRIVATE(node); 710 struct mbuf *m; 711 struct sscfu_arg arg; 712 int error; 713 714 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) 715 dump_saal_signal(node, sig, msg, 1); 716 717 if (priv->lower == NULL) { 718 if (msg != NULL) 719 uni_msg_destroy(msg); 720 return; 721 } 722 723 arg.sig = sig; 724 725 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); 726 if (msg != NULL) 727 uni_msg_destroy(msg); 728 if (m == NULL) 729 return; 730 731 NG_SEND_DATA_ONLY(error, priv->lower, m); 732} 733 734static void 735uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...) 736{ 737 va_list ap; 738 739 static char *facnames[] = { 740#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D, 741 UNI_DEBUG_FACILITIES 742#undef UNI_DEBUG_DEFINE 743 }; 744 745 printf("%s: ", facnames[fac]); 746 747 va_start(ap, fmt); 748 vprintf(fmt, ap); 749 va_end(ap); 750 751 printf("\n"); 752} 753 754/************************************************************/ 755/* 756 * Memory debugging 757 */ 758struct unimem_debug { 759 const char *file; 760 u_int lno; 761 LIST_ENTRY(unimem_debug) link; 762 char data[0]; 763}; 764LIST_HEAD(unimem_debug_list, unimem_debug); 765 766static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = { 767 LIST_HEAD_INITIALIZER(nguni_freemem[0]), 768 LIST_HEAD_INITIALIZER(nguni_freemem[1]), 769 LIST_HEAD_INITIALIZER(nguni_freemem[2]), 770 LIST_HEAD_INITIALIZER(nguni_freemem[3]), 771 LIST_HEAD_INITIALIZER(nguni_freemem[4]), 772}; 773static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = { 774 LIST_HEAD_INITIALIZER(nguni_usedmem[0]), 775 LIST_HEAD_INITIALIZER(nguni_usedmem[1]), 776 LIST_HEAD_INITIALIZER(nguni_usedmem[2]), 777 LIST_HEAD_INITIALIZER(nguni_usedmem[3]), 778 LIST_HEAD_INITIALIZER(nguni_usedmem[4]), 779}; 780 781static struct mtx nguni_unilist_mtx; 782 783static const char *unimem_names[UNIMEM_TYPES] = { 784 "instance", 785 "all", 786 "signal", 787 "call", 788 "party" 789}; 790 791static void 792uni_init(void) 793{ 794 mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL, 795 MTX_DEF); 796} 797 798static void 799uni_fini(void) 800{ 801 u_int type; 802 struct unimem_debug *h; 803 804 for (type = 0; type < UNIMEM_TYPES; type++) { 805 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) { 806 LIST_REMOVE(h, link); 807 free(h, M_UNI); 808 } 809 810 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) { 811 LIST_REMOVE(h, link); 812 printf("ng_uni: %s in use: %p (%s,%u)\n", 813 unimem_names[type], (caddr_t)h->data, 814 h->file, h->lno); 815 free(h, M_UNI); 816 } 817 } 818 819 mtx_destroy(&nguni_unilist_mtx); 820} 821 822/* 823 * Allocate a chunk of memory from a given type. 824 */ 825void * 826ng_uni_malloc(enum unimem type, const char *file, u_int lno) 827{ 828 struct unimem_debug *d; 829 size_t full; 830 831 /* 832 * Try to allocate 833 */ 834 mtx_lock(&nguni_unilist_mtx); 835 if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL) 836 LIST_REMOVE(d, link); 837 mtx_unlock(&nguni_unilist_mtx); 838 839 if (d == NULL) { 840 /* 841 * allocate 842 */ 843 full = unimem_sizes[type] + offsetof(struct unimem_debug, data); 844 if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL) 845 return (NULL); 846 } else { 847 bzero(d->data, unimem_sizes[type]); 848 } 849 d->file = file; 850 d->lno = lno; 851 852 mtx_lock(&nguni_unilist_mtx); 853 LIST_INSERT_HEAD(&nguni_usedmem[type], d, link); 854 mtx_unlock(&nguni_unilist_mtx); 855 return (d->data); 856} 857 858void 859ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno) 860{ 861 struct unimem_debug *d, *h; 862 863 d = (struct unimem_debug *) 864 ((char *)ptr - offsetof(struct unimem_debug, data)); 865 866 mtx_lock(&nguni_unilist_mtx); 867 868 LIST_FOREACH(h, &nguni_usedmem[type], link) 869 if (d == h) 870 break; 871 872 if (h != NULL) { 873 LIST_REMOVE(d, link); 874 LIST_INSERT_HEAD(&nguni_freemem[type], d, link); 875 } else { 876 /* 877 * Not on used list - try free list. 878 */ 879 LIST_FOREACH(h, &nguni_freemem[type], link) 880 if (d == h) 881 break; 882 if (h == NULL) 883 printf("ng_uni: %s,%u: %p(%s) was never allocated\n", 884 file, lno, ptr, unimem_names[type]); 885 else 886 printf("ng_uni: %s,%u: %p(%s) was already destroyed " 887 "in %s,%u\n", 888 file, lno, ptr, unimem_names[type], 889 h->file, h->lno); 890 } 891 mtx_unlock(&nguni_unilist_mtx); 892} 893/************************************************************/ 894/* 895 * INITIALISATION 896 */ 897 898/* 899 * Loading and unloading of node type 900 */ 901static int 902ng_uni_mod_event(module_t mod, int event, void *data) 903{ 904 int error = 0; 905 906 switch(event) { 907 case MOD_LOAD: 908 uni_init(); 909 break; 910 911 case MOD_UNLOAD: 912 uni_fini(); 913 break; 914 915 default: 916 error = EOPNOTSUPP; 917 break; 918 } 919 return (error); 920} 921