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