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 319 case NGM_GENERIC_COOKIE: 320 switch (msg->header.cmd) { 321 322 case NGM_TEXT_STATUS: 323 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 324 if (resp == NULL) { 325 error = ENOMEM; 326 break; 327 } 328 329 resp->header.arglen = text_status(node, priv, 330 (char *)resp->data, resp->header.arglen) + 1; 331 break; 332 333 default: 334 error = EINVAL; 335 break; 336 } 337 break; 338 339 case NGM_UNI_COOKIE: 340 switch (msg->header.cmd) { 341 342 case NGM_UNI_SETDEBUG: 343 { 344 struct ngm_uni_debug *arg; 345 346 if (msg->header.arglen > sizeof(*arg)) { 347 error = EINVAL; 348 break; 349 } 350 arg = (struct ngm_uni_debug *)msg->data; 351 for (i = 0; i < UNI_MAXFACILITY; i++) 352 uni_set_debug(priv->uni, i, arg->level[i]); 353 break; 354 } 355 356 case NGM_UNI_GETDEBUG: 357 { 358 struct ngm_uni_debug *arg; 359 360 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 361 if(resp == NULL) { 362 error = ENOMEM; 363 break; 364 } 365 arg = (struct ngm_uni_debug *)resp->data; 366 for (i = 0; i < UNI_MAXFACILITY; i++) 367 arg->level[i] = uni_get_debug(priv->uni, i); 368 break; 369 } 370 371 case NGM_UNI_GET_CONFIG: 372 { 373 struct uni_config *config; 374 375 if (msg->header.arglen != 0) { 376 error = EINVAL; 377 break; 378 } 379 NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT); 380 if (resp == NULL) { 381 error = ENOMEM; 382 break; 383 } 384 config = (struct uni_config *)resp->data; 385 uni_get_config(priv->uni, config); 386 387 break; 388 } 389 390 case NGM_UNI_SET_CONFIG: 391 { 392 struct ngm_uni_set_config *arg; 393 struct ngm_uni_config_mask *mask; 394 395 if (msg->header.arglen != sizeof(*arg)) { 396 error = EINVAL; 397 break; 398 } 399 arg = (struct ngm_uni_set_config *)msg->data; 400 401 NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT); 402 if (resp == NULL) { 403 error = ENOMEM; 404 break; 405 } 406 mask = (struct ngm_uni_config_mask *)resp->data; 407 408 *mask = arg->mask; 409 410 uni_set_config(priv->uni, &arg->config, 411 &mask->mask, &mask->popt_mask, &mask->option_mask); 412 413 break; 414 } 415 416 case NGM_UNI_ENABLE: 417 if (msg->header.arglen != 0) { 418 error = EINVAL; 419 break; 420 } 421 if (priv->enabled) { 422 error = EISCONN; 423 break; 424 } 425 priv->enabled = 1; 426 break; 427 428 case NGM_UNI_DISABLE: 429 if (msg->header.arglen != 0) { 430 error = EINVAL; 431 break; 432 } 433 if (!priv->enabled) { 434 error = ENOTCONN; 435 break; 436 } 437 priv->enabled = 0; 438 uni_reset(priv->uni); 439 break; 440 441 case NGM_UNI_GETSTATE: 442 if (msg->header.arglen != 0) { 443 error = EINVAL; 444 break; 445 } 446 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 447 if(resp == NULL) { 448 error = ENOMEM; 449 break; 450 } 451 *(u_int32_t *)resp->data = 452 priv->enabled ? (uni_getcustate(priv->uni) + 1) 453 : 0; 454 break; 455 456 default: 457 error = EINVAL; 458 break; 459 } 460 break; 461 462 default: 463 error = EINVAL; 464 break; 465 } 466 467 NG_RESPOND_MSG(error, node, item, resp); 468 NG_FREE_MSG(msg); 469 return (error); 470} 471 472/************************************************************/ 473/* 474 * HOOK MANAGEMENT 475 */ 476static int 477ng_uni_newhook(node_p node, hook_p hook, const char *name) 478{ 479 struct priv *priv = NG_NODE_PRIVATE(node); 480 481 if (strcmp(name, "lower") == 0) { 482 priv->lower = hook; 483 } else if(strcmp(name, "upper") == 0) { 484 priv->upper = hook; 485 NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper); 486 } else 487 return EINVAL; 488 489 return 0; 490} 491 492static int 493ng_uni_disconnect(hook_p hook) 494{ 495 node_p node = NG_HOOK_NODE(hook); 496 struct priv *priv = NG_NODE_PRIVATE(node); 497 498 if(hook == priv->lower) 499 priv->lower = NULL; 500 else if(hook == priv->upper) 501 priv->upper = NULL; 502 else 503 printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook)); 504 505 if (NG_NODE_NUMHOOKS(node) == 0) { 506 if (NG_NODE_IS_VALID(node)) 507 ng_rmnode_self(node); 508 } 509 510 return (0); 511} 512 513/************************************************************/ 514/* 515 * DATA 516 */ 517/* 518 * Receive signal from USER. 519 * 520 * Repackage the data into one large buffer. 521 */ 522static int 523ng_uni_rcvupper(hook_p hook, item_p item) 524{ 525 node_p node = NG_HOOK_NODE(hook); 526 struct priv *priv = NG_NODE_PRIVATE(node); 527 struct mbuf *m; 528 struct uni_arg arg; 529 struct uni_msg *msg; 530 int error; 531 532 if (!priv->enabled) { 533 NG_FREE_ITEM(item); 534 return (ENOTCONN); 535 } 536 537 NGI_GET_M(item, m); 538 NG_FREE_ITEM(item); 539 540 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { 541 m_freem(m); 542 return (error); 543 } 544 m_freem(m); 545 546 if (uni_msg_len(msg) < sizeof(arg)) { 547 printf("%s: packet too short\n", __func__); 548 uni_msg_destroy(msg); 549 return (EINVAL); 550 } 551 552 bcopy(msg->b_rptr, &arg, sizeof(arg)); 553 msg->b_rptr += sizeof(arg); 554 555 if (arg.sig >= UNIAPI_MAXSIG) { 556 printf("%s: bogus signal\n", __func__); 557 uni_msg_destroy(msg); 558 return (EINVAL); 559 } 560 uni_uni_input(priv->uni, arg.sig, arg.cookie, msg); 561 uni_work(priv->uni); 562 563 return (0); 564} 565 566 567/* 568 * Upper layer signal from UNI 569 */ 570static void 571uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie, 572 struct uni_msg *msg) 573{ 574 node_p node = (node_p)varg; 575 struct priv *priv = NG_NODE_PRIVATE(node); 576 struct mbuf *m; 577 struct uni_arg arg; 578 int error; 579 580 if (priv->upper == NULL) { 581 if (msg != NULL) 582 uni_msg_destroy(msg); 583 return; 584 } 585 arg.sig = sig; 586 arg.cookie = cookie; 587 588 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); 589 if (msg != NULL) 590 uni_msg_destroy(msg); 591 if (m == NULL) 592 return; 593 594 NG_SEND_DATA_ONLY(error, priv->upper, m); 595} 596 597 598static void 599dump_uni_msg(struct uni_msg *msg) 600{ 601 u_int pos; 602 603 for (pos = 0; pos < uni_msg_len(msg); pos++) { 604 if (pos % 16 == 0) 605 printf("%06o ", pos); 606 if (pos % 16 == 8) 607 printf(" "); 608 printf(" %02x", msg->b_rptr[pos]); 609 if (pos % 16 == 15) 610 printf("\n"); 611 } 612 if (pos % 16 != 0) 613 printf("\n"); 614} 615 616 617/* 618 * Dump a SAAL signal in either direction 619 */ 620static void 621dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to) 622{ 623 struct priv *priv = NG_NODE_PRIVATE(node); 624 625 printf("signal %s SAAL: ", to ? "to" : "from"); 626 627 switch (sig) { 628 629#define D(S) case S: printf("%s", #S); break 630 631 D(SAAL_ESTABLISH_request); 632 D(SAAL_ESTABLISH_indication); 633 D(SAAL_ESTABLISH_confirm); 634 D(SAAL_RELEASE_request); 635 D(SAAL_RELEASE_confirm); 636 D(SAAL_RELEASE_indication); 637 D(SAAL_DATA_request); 638 D(SAAL_DATA_indication); 639 D(SAAL_UDATA_request); 640 D(SAAL_UDATA_indication); 641 642#undef D 643 default: 644 printf("sig=%d", sig); break; 645 } 646 if (msg != NULL) { 647 printf(" data=%zu\n", uni_msg_len(msg)); 648 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1) 649 dump_uni_msg(msg); 650 } else 651 printf("\n"); 652} 653 654/* 655 * Receive signal from SSCOP. 656 * 657 * If this is a data signal, repackage the data into one large buffer. 658 * UNI shouldn't be the bottleneck in a system and this greatly simplifies 659 * parsing in UNI. 660 */ 661static int 662ng_uni_rcvlower(hook_p hook __unused, item_p item) 663{ 664 node_p node = NG_HOOK_NODE(hook); 665 struct priv *priv = NG_NODE_PRIVATE(node); 666 struct mbuf *m; 667 struct sscfu_arg arg; 668 struct uni_msg *msg; 669 int error; 670 671 if (!priv->enabled) { 672 NG_FREE_ITEM(item); 673 return (ENOTCONN); 674 } 675 676 NGI_GET_M(item, m); 677 NG_FREE_ITEM(item); 678 679 if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) { 680 m_freem(m); 681 return (error); 682 } 683 m_freem(m); 684 685 if (uni_msg_len(msg) < sizeof(arg)) { 686 uni_msg_destroy(msg); 687 printf("%s: packet too short\n", __func__); 688 return (EINVAL); 689 } 690 bcopy(msg->b_rptr, &arg, sizeof(arg)); 691 msg->b_rptr += sizeof(arg); 692 693 if (arg.sig > SAAL_UDATA_indication) { 694 uni_msg_destroy(msg); 695 printf("%s: bogus signal\n", __func__); 696 return (EINVAL); 697 } 698 699 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) 700 dump_saal_signal(node, arg.sig, msg, 0); 701 702 uni_saal_input(priv->uni, arg.sig, msg); 703 uni_work(priv->uni); 704 705 return (0); 706} 707 708/* 709 * Send signal to sscop. 710 * Pack the message into an mbuf chain. 711 */ 712static void 713uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg) 714{ 715 node_p node = (node_p)varg; 716 struct priv *priv = NG_NODE_PRIVATE(node); 717 struct mbuf *m; 718 struct sscfu_arg arg; 719 int error; 720 721 if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0) 722 dump_saal_signal(node, sig, msg, 1); 723 724 if (priv->lower == NULL) { 725 if (msg != NULL) 726 uni_msg_destroy(msg); 727 return; 728 } 729 730 arg.sig = sig; 731 732 m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg)); 733 if (msg != NULL) 734 uni_msg_destroy(msg); 735 if (m == NULL) 736 return; 737 738 NG_SEND_DATA_ONLY(error, priv->lower, m); 739} 740 741static void 742uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...) 743{ 744 va_list ap; 745 746 static char *facnames[] = { 747#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D, 748 UNI_DEBUG_FACILITIES 749#undef UNI_DEBUG_DEFINE 750 }; 751 752 printf("%s: ", facnames[fac]); 753 754 va_start(ap, fmt); 755 vprintf(fmt, ap); 756 va_end(ap); 757 758 printf("\n"); 759} 760 761 762/************************************************************/ 763/* 764 * Memory debugging 765 */ 766struct unimem_debug { 767 const char *file; 768 u_int lno; 769 LIST_ENTRY(unimem_debug) link; 770 char data[0]; 771}; 772LIST_HEAD(unimem_debug_list, unimem_debug); 773 774static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = { 775 LIST_HEAD_INITIALIZER(nguni_freemem[0]), 776 LIST_HEAD_INITIALIZER(nguni_freemem[1]), 777 LIST_HEAD_INITIALIZER(nguni_freemem[2]), 778 LIST_HEAD_INITIALIZER(nguni_freemem[3]), 779 LIST_HEAD_INITIALIZER(nguni_freemem[4]), 780}; 781static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = { 782 LIST_HEAD_INITIALIZER(nguni_usedmem[0]), 783 LIST_HEAD_INITIALIZER(nguni_usedmem[1]), 784 LIST_HEAD_INITIALIZER(nguni_usedmem[2]), 785 LIST_HEAD_INITIALIZER(nguni_usedmem[3]), 786 LIST_HEAD_INITIALIZER(nguni_usedmem[4]), 787}; 788 789static struct mtx nguni_unilist_mtx; 790 791static const char *unimem_names[UNIMEM_TYPES] = { 792 "instance", 793 "all", 794 "signal", 795 "call", 796 "party" 797}; 798 799static void 800uni_init(void) 801{ 802 mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL, 803 MTX_DEF); 804} 805 806static void 807uni_fini(void) 808{ 809 u_int type; 810 struct unimem_debug *h; 811 812 for (type = 0; type < UNIMEM_TYPES; type++) { 813 while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) { 814 LIST_REMOVE(h, link); 815 free(h, M_UNI); 816 } 817 818 while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) { 819 LIST_REMOVE(h, link); 820 printf("ng_uni: %s in use: %p (%s,%u)\n", 821 unimem_names[type], (caddr_t)h->data, 822 h->file, h->lno); 823 free(h, M_UNI); 824 } 825 } 826 827 mtx_destroy(&nguni_unilist_mtx); 828} 829 830/* 831 * Allocate a chunk of memory from a given type. 832 */ 833void * 834ng_uni_malloc(enum unimem type, const char *file, u_int lno) 835{ 836 struct unimem_debug *d; 837 size_t full; 838 839 /* 840 * Try to allocate 841 */ 842 mtx_lock(&nguni_unilist_mtx); 843 if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL) 844 LIST_REMOVE(d, link); 845 mtx_unlock(&nguni_unilist_mtx); 846 847 if (d == NULL) { 848 /* 849 * allocate 850 */ 851 full = unimem_sizes[type] + offsetof(struct unimem_debug, data); 852 if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL) 853 return (NULL); 854 } else { 855 bzero(d->data, unimem_sizes[type]); 856 } 857 d->file = file; 858 d->lno = lno; 859 860 mtx_lock(&nguni_unilist_mtx); 861 LIST_INSERT_HEAD(&nguni_usedmem[type], d, link); 862 mtx_unlock(&nguni_unilist_mtx); 863 return (d->data); 864} 865 866void 867ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno) 868{ 869 struct unimem_debug *d, *h; 870 871 d = (struct unimem_debug *) 872 ((char *)ptr - offsetof(struct unimem_debug, data)); 873 874 mtx_lock(&nguni_unilist_mtx); 875 876 LIST_FOREACH(h, &nguni_usedmem[type], link) 877 if (d == h) 878 break; 879 880 if (h != NULL) { 881 LIST_REMOVE(d, link); 882 LIST_INSERT_HEAD(&nguni_freemem[type], d, link); 883 } else { 884 /* 885 * Not on used list - try free list. 886 */ 887 LIST_FOREACH(h, &nguni_freemem[type], link) 888 if (d == h) 889 break; 890 if (h == NULL) 891 printf("ng_uni: %s,%u: %p(%s) was never allocated\n", 892 file, lno, ptr, unimem_names[type]); 893 else 894 printf("ng_uni: %s,%u: %p(%s) was already destroyed " 895 "in %s,%u\n", 896 file, lno, ptr, unimem_names[type], 897 h->file, h->lno); 898 } 899 mtx_unlock(&nguni_unilist_mtx); 900} 901/************************************************************/ 902/* 903 * INITIALISATION 904 */ 905 906/* 907 * Loading and unloading of node type 908 */ 909static int 910ng_uni_mod_event(module_t mod, int event, void *data) 911{ 912 int error = 0; 913 914 switch(event) { 915 916 case MOD_LOAD: 917 uni_init(); 918 break; 919 920 case MOD_UNLOAD: 921 uni_fini(); 922 break; 923 924 default: 925 error = EOPNOTSUPP; 926 break; 927 } 928 return (error); 929} 930