1 2 /* 3 * ng_base.c 4 * 5 * Copyright (c) 1996-1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Authors: Julian Elischer <julian@freebsd.org> 38 * Archie Cobbs <archie@freebsd.org> 39 * 40 * $FreeBSD: src/sys/netgraph/ng_base.c,v 1.11.2.17 2002/07/02 23:44:02 archie Exp $ 41 * $DragonFly: src/sys/netgraph/netgraph/ng_base.c,v 1.28 2008/09/24 14:26:39 sephe Exp $ 42 * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 43 */ 44 45 /* 46 * This file implements the base netgraph code. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/errno.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 #include <sys/syslog.h> 55 #include <sys/linker.h> 56 #include <sys/queue.h> 57 #include <sys/mbuf.h> 58 #include <sys/ctype.h> 59 #include <sys/sysctl.h> 60 #include <sys/vnode.h> 61 #include <machine/limits.h> 62 63 #include <sys/thread2.h> 64 #include <sys/msgport2.h> 65 66 #include <net/netisr.h> 67 68 #include <netgraph/ng_message.h> 69 #include <netgraph/netgraph.h> 70 #include <netgraph/ng_parse.h> 71 72 MODULE_VERSION(netgraph, NG_ABI_VERSION); 73 74 /* List of all nodes */ 75 static LIST_HEAD(, ng_node) nodelist; 76 77 /* List of installed types */ 78 static LIST_HEAD(, ng_type) typelist; 79 80 /* Hash releted definitions */ 81 #define ID_HASH_SIZE 32 /* most systems wont need even this many */ 82 static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE]; 83 /* Don't nead to initialise them because it's a LIST */ 84 85 /* Internal functions */ 86 static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 87 static int ng_connect(hook_p hook1, hook_p hook2); 88 static void ng_disconnect_hook(hook_p hook); 89 static int ng_generic_msg(node_p here, struct ng_mesg *msg, 90 const char *retaddr, struct ng_mesg ** resp); 91 static ng_ID_t ng_decodeidname(const char *name); 92 static int ngb_mod_event(module_t mod, int event, void *data); 93 static void ngintr(struct netmsg *); 94 static int ng_load_module(const char *); 95 static int ng_unload_module(const char *); 96 97 /* Our own netgraph malloc type */ 98 MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 99 100 /* Set this to Debugger("X") to catch all errors as they occur */ 101 #ifndef TRAP_ERROR 102 #define TRAP_ERROR 103 #endif 104 105 static ng_ID_t nextID = 1; 106 107 #ifdef INVARIANTS 108 #define CHECK_DATA_MBUF(m) do { \ 109 struct mbuf *n; \ 110 int total; \ 111 \ 112 if (((m)->m_flags & M_PKTHDR) == 0) \ 113 panic("%s: !PKTHDR", __func__); \ 114 for (total = 0, n = (m); n != NULL; n = n->m_next) \ 115 total += n->m_len; \ 116 if ((m)->m_pkthdr.len != total) { \ 117 panic("%s: %d != %d", \ 118 __func__, (m)->m_pkthdr.len, total); \ 119 } \ 120 } while (0) 121 #else 122 #define CHECK_DATA_MBUF(m) 123 #endif 124 125 126 /************************************************************************ 127 Parse type definitions for generic messages 128 ************************************************************************/ 129 130 /* Handy structure parse type defining macro */ 131 #define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 132 static const struct ng_parse_struct_field \ 133 ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 134 static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 135 &ng_parse_struct_type, \ 136 &ng_ ## lo ## _type_fields \ 137 } 138 139 DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 140 DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 141 DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 142 DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 143 DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 144 DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 145 DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 146 147 /* Get length of an array when the length is stored as a 32 bit 148 value immediately preceeding the array -- as with struct namelist 149 and struct typelist. */ 150 static int 151 ng_generic_list_getLength(const struct ng_parse_type *type, 152 const u_char *start, const u_char *buf) 153 { 154 return *((const u_int32_t *)(buf - 4)); 155 } 156 157 /* Get length of the array of struct linkinfo inside a struct hooklist */ 158 static int 159 ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 160 const u_char *start, const u_char *buf) 161 { 162 const struct hooklist *hl = (const struct hooklist *)start; 163 164 return hl->nodeinfo.hooks; 165 } 166 167 /* Array type for a variable length array of struct namelist */ 168 static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 169 &ng_generic_nodeinfo_type, 170 &ng_generic_list_getLength 171 }; 172 static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 173 &ng_parse_array_type, 174 &ng_nodeinfoarray_type_info 175 }; 176 177 /* Array type for a variable length array of struct typelist */ 178 static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 179 &ng_generic_typeinfo_type, 180 &ng_generic_list_getLength 181 }; 182 static const struct ng_parse_type ng_generic_typeinfoarray_type = { 183 &ng_parse_array_type, 184 &ng_typeinfoarray_type_info 185 }; 186 187 /* Array type for array of struct linkinfo in struct hooklist */ 188 static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 189 &ng_generic_linkinfo_type, 190 &ng_generic_linkinfo_getLength 191 }; 192 static const struct ng_parse_type ng_generic_linkinfo_array_type = { 193 &ng_parse_array_type, 194 &ng_generic_linkinfo_array_type_info 195 }; 196 197 DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 198 DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 199 (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 200 DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 201 (&ng_generic_nodeinfoarray_type)); 202 203 /* List of commands and how to convert arguments to/from ASCII */ 204 static const struct ng_cmdlist ng_generic_cmds[] = { 205 { 206 NGM_GENERIC_COOKIE, 207 NGM_SHUTDOWN, 208 "shutdown", 209 NULL, 210 NULL 211 }, 212 { 213 NGM_GENERIC_COOKIE, 214 NGM_MKPEER, 215 "mkpeer", 216 &ng_generic_mkpeer_type, 217 NULL 218 }, 219 { 220 NGM_GENERIC_COOKIE, 221 NGM_CONNECT, 222 "connect", 223 &ng_generic_connect_type, 224 NULL 225 }, 226 { 227 NGM_GENERIC_COOKIE, 228 NGM_NAME, 229 "name", 230 &ng_generic_name_type, 231 NULL 232 }, 233 { 234 NGM_GENERIC_COOKIE, 235 NGM_RMHOOK, 236 "rmhook", 237 &ng_generic_rmhook_type, 238 NULL 239 }, 240 { 241 NGM_GENERIC_COOKIE, 242 NGM_NODEINFO, 243 "nodeinfo", 244 NULL, 245 &ng_generic_nodeinfo_type 246 }, 247 { 248 NGM_GENERIC_COOKIE, 249 NGM_LISTHOOKS, 250 "listhooks", 251 NULL, 252 &ng_generic_hooklist_type 253 }, 254 { 255 NGM_GENERIC_COOKIE, 256 NGM_LISTNAMES, 257 "listnames", 258 NULL, 259 &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 260 }, 261 { 262 NGM_GENERIC_COOKIE, 263 NGM_LISTNODES, 264 "listnodes", 265 NULL, 266 &ng_generic_listnodes_type 267 }, 268 { 269 NGM_GENERIC_COOKIE, 270 NGM_LISTTYPES, 271 "listtypes", 272 NULL, 273 &ng_generic_typeinfo_type 274 }, 275 { 276 NGM_GENERIC_COOKIE, 277 NGM_TEXT_CONFIG, 278 "textconfig", 279 NULL, 280 &ng_parse_string_type 281 }, 282 { 283 NGM_GENERIC_COOKIE, 284 NGM_TEXT_STATUS, 285 "textstatus", 286 NULL, 287 &ng_parse_string_type 288 }, 289 { 290 NGM_GENERIC_COOKIE, 291 NGM_ASCII2BINARY, 292 "ascii2binary", 293 &ng_parse_ng_mesg_type, 294 &ng_parse_ng_mesg_type 295 }, 296 { 297 NGM_GENERIC_COOKIE, 298 NGM_BINARY2ASCII, 299 "binary2ascii", 300 &ng_parse_ng_mesg_type, 301 &ng_parse_ng_mesg_type 302 }, 303 { 0 } 304 }; 305 306 /************************************************************************ 307 Node routines 308 ************************************************************************/ 309 310 static int 311 linker_api_available(void) 312 { 313 /* linker_* API won't work without a process context */ 314 if (curproc == NULL) 315 return 0; 316 /* 317 * nlookup_init() relies on namei_oc to be initialized, 318 * but it's not when the netgraph module is loaded during boot. 319 */ 320 if (namei_oc == NULL) 321 return 0; 322 return 1; 323 } 324 325 static int 326 ng_load_module(const char *name) 327 { 328 char *path, filename[NG_TYPESIZ + 3]; 329 linker_file_t lf; 330 int error; 331 332 if (!linker_api_available()) 333 return (ENXIO); 334 335 /* Not found, try to load it as a loadable module */ 336 ksnprintf(filename, sizeof(filename), "ng_%s.ko", name); 337 if ((path = linker_search_path(filename)) == NULL) 338 return (ENXIO); 339 error = linker_load_file(path, &lf); 340 FREE(path, M_LINKER); 341 if (error == 0) 342 lf->userrefs++; /* pretend kldload'ed */ 343 return (error); 344 } 345 346 static int 347 ng_unload_module(const char *name) 348 { 349 char filename[NG_TYPESIZ + 3]; 350 linker_file_t lf; 351 int error; 352 353 if (!linker_api_available()) 354 return (ENXIO); 355 356 /* Not found, try to load it as a loadable module */ 357 ksnprintf(filename, sizeof(filename), "ng_%s.ko", name); 358 if ((lf = linker_find_file_by_name(filename)) == NULL) 359 return (ENXIO); 360 lf->userrefs--; /* pretend kldunload'ed */ 361 error = linker_file_unload(lf); 362 if (error) 363 lf->userrefs++; 364 365 return (error); 366 } 367 368 /* 369 * Instantiate a node of the requested type 370 */ 371 int 372 ng_make_node(const char *typename, node_p *nodepp) 373 { 374 struct ng_type *type; 375 376 /* Check that the type makes sense */ 377 if (typename == NULL) { 378 TRAP_ERROR; 379 return (EINVAL); 380 } 381 382 /* Locate the node type */ 383 if ((type = ng_findtype(typename)) == NULL) 384 return (ENXIO); 385 386 /* Call the constructor */ 387 if (type->constructor != NULL) 388 return ((*type->constructor)(nodepp)); 389 else 390 return (ng_make_node_common(type, nodepp)); 391 } 392 393 /* 394 * Generic node creation. Called by node constructors. 395 * The returned node has a reference count of 1. 396 */ 397 int 398 ng_make_node_common(struct ng_type *type, node_p *nodepp) 399 { 400 node_p node; 401 402 /* Require the node type to have been already installed */ 403 if (ng_findtype(type->name) == NULL) { 404 TRAP_ERROR; 405 return (EINVAL); 406 } 407 408 /* Make a node and try attach it to the type */ 409 MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_NOWAIT | M_ZERO); 410 if (node == NULL) { 411 TRAP_ERROR; 412 return (ENOMEM); 413 } 414 node->type = type; 415 node->refs++; /* note reference */ 416 type->refs++; 417 418 /* Link us into the node linked list */ 419 LIST_INSERT_HEAD(&nodelist, node, nodes); 420 421 /* Initialize hook list for new node */ 422 LIST_INIT(&node->hooks); 423 424 /* get an ID and put us in the hash chain */ 425 node->ID = nextID++; /* 137 per second for 1 year before wrap */ 426 LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes); 427 428 /* Done */ 429 *nodepp = node; 430 return (0); 431 } 432 433 /* 434 * Forceably start the shutdown process on a node. Either call 435 * it's shutdown method, or do the default shutdown if there is 436 * no type-specific method. 437 * 438 * Persistent nodes must have a type-specific method which 439 * resets the NG_INVALID flag. 440 */ 441 void 442 ng_rmnode(node_p node) 443 { 444 /* Check if it's already shutting down */ 445 if ((node->flags & NG_INVALID) != 0) 446 return; 447 448 /* Add an extra reference so it doesn't go away during this */ 449 node->refs++; 450 451 /* Mark it invalid so any newcomers know not to try use it */ 452 node->flags |= NG_INVALID; 453 454 /* Ask the type if it has anything to do in this case */ 455 if (node->type && node->type->shutdown) 456 (*node->type->shutdown)(node); 457 else { /* do the default thing */ 458 ng_unname(node); 459 ng_cutlinks(node); 460 ng_unref(node); 461 } 462 463 /* Remove extra reference, possibly the last */ 464 ng_unref(node); 465 } 466 467 /* 468 * Called by the destructor to remove any STANDARD external references 469 */ 470 void 471 ng_cutlinks(node_p node) 472 { 473 hook_p hook; 474 475 /* Make sure that this is set to stop infinite loops */ 476 node->flags |= NG_INVALID; 477 478 /* If we have sleepers, wake them up; they'll see NG_INVALID */ 479 if (node->sleepers) 480 wakeup(node); 481 482 /* Notify all remaining connected nodes to disconnect */ 483 while ((hook = LIST_FIRST(&node->hooks)) != NULL) 484 ng_destroy_hook(hook); 485 } 486 487 /* 488 * Remove a reference to the node, possibly the last 489 */ 490 void 491 ng_unref(node_p node) 492 { 493 crit_enter(); 494 if (--node->refs <= 0) { 495 node->type->refs--; 496 LIST_REMOVE(node, nodes); 497 LIST_REMOVE(node, idnodes); 498 FREE(node, M_NETGRAPH); 499 } 500 crit_exit(); 501 } 502 503 /* 504 * Wait for a node to come ready. Returns a node with a reference count; 505 * don't forget to drop it when we are done with it using ng_release_node(). 506 */ 507 int 508 ng_wait_node(node_p node, char *msg) 509 { 510 int error = 0; 511 512 if (msg == NULL) 513 msg = "netgraph"; 514 crit_enter(); 515 node->sleepers++; 516 node->refs++; /* the sleeping process counts as a reference */ 517 while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY) 518 error = tsleep(node, PCATCH, msg, 0); 519 node->sleepers--; 520 if (node->flags & NG_INVALID) { 521 TRAP_ERROR; 522 error = ENXIO; 523 } else { 524 KASSERT(node->refs > 1, 525 ("%s: refs=%d", __func__, node->refs)); 526 node->flags |= NG_BUSY; 527 } 528 crit_exit(); 529 530 /* Release the reference we had on it */ 531 if (error != 0) 532 ng_unref(node); 533 return error; 534 } 535 536 /* 537 * Release a node acquired via ng_wait_node() 538 */ 539 void 540 ng_release_node(node_p node) 541 { 542 /* Declare that we don't want it */ 543 node->flags &= ~NG_BUSY; 544 545 /* If we have sleepers, then wake them up */ 546 if (node->sleepers) 547 wakeup(node); 548 549 /* We also have a reference.. drop it too */ 550 ng_unref(node); 551 } 552 553 /************************************************************************ 554 Node ID handling 555 ************************************************************************/ 556 static node_p 557 ng_ID2node(ng_ID_t ID) 558 { 559 node_p np; 560 LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) { 561 if ((np->flags & NG_INVALID) == 0 && np->ID == ID) 562 break; 563 } 564 return(np); 565 } 566 567 ng_ID_t 568 ng_node2ID(node_p node) 569 { 570 return (node->ID); 571 } 572 573 /************************************************************************ 574 Node name handling 575 ************************************************************************/ 576 577 /* 578 * Assign a node a name. Once assigned, the name cannot be changed. 579 */ 580 int 581 ng_name_node(node_p node, const char *name) 582 { 583 int i; 584 585 /* Check the name is valid */ 586 for (i = 0; i < NG_NODESIZ; i++) { 587 if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 588 break; 589 } 590 if (i == 0 || name[i] != '\0') { 591 TRAP_ERROR; 592 return (EINVAL); 593 } 594 if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 595 TRAP_ERROR; 596 return (EINVAL); 597 } 598 599 /* Check the node isn't already named */ 600 if (node->name != NULL) { 601 TRAP_ERROR; 602 return (EISCONN); 603 } 604 605 /* Check the name isn't already being used */ 606 if (ng_findname(node, name) != NULL) { 607 TRAP_ERROR; 608 return (EADDRINUSE); 609 } 610 611 /* Allocate space and copy it */ 612 MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT); 613 if (node->name == NULL) { 614 TRAP_ERROR; 615 return (ENOMEM); 616 } 617 strcpy(node->name, name); 618 619 /* The name counts as a reference */ 620 node->refs++; 621 return (0); 622 } 623 624 /* 625 * Find a node by absolute name. The name should NOT end with ':' 626 * The name "." means "this node" and "[xxx]" means "the node 627 * with ID (ie, at address) xxx". 628 * 629 * Returns the node if found, else NULL. 630 */ 631 node_p 632 ng_findname(node_p this, const char *name) 633 { 634 node_p node; 635 ng_ID_t temp; 636 637 /* "." means "this node" */ 638 if (strcmp(name, ".") == 0) 639 return(this); 640 641 /* Check for name-by-ID */ 642 if ((temp = ng_decodeidname(name)) != 0) { 643 return (ng_ID2node(temp)); 644 } 645 646 /* Find node by name */ 647 LIST_FOREACH(node, &nodelist, nodes) { 648 if ((node->name != NULL) 649 && (strcmp(node->name, name) == 0) 650 && ((node->flags & NG_INVALID) == 0)) 651 break; 652 } 653 return (node); 654 } 655 656 /* 657 * Decode a ID name, eg. "[f03034de]". Returns 0 if the 658 * string is not valid, otherwise returns the value. 659 */ 660 static ng_ID_t 661 ng_decodeidname(const char *name) 662 { 663 const int len = strlen(name); 664 char *eptr; 665 u_long val; 666 667 /* Check for proper length, brackets, no leading junk */ 668 if (len < 3 || name[0] != '[' || name[len - 1] != ']' 669 || !isxdigit(name[1])) 670 return (0); 671 672 /* Decode number */ 673 val = strtoul(name + 1, &eptr, 16); 674 if (eptr - name != len - 1 || val == ULONG_MAX || val == 0) 675 return ((ng_ID_t)0); 676 return (ng_ID_t)val; 677 } 678 679 /* 680 * Remove a name from a node. This should only be called 681 * when shutting down and removing the node. 682 */ 683 void 684 ng_unname(node_p node) 685 { 686 if (node->name) { 687 FREE(node->name, M_NETGRAPH); 688 node->name = NULL; 689 ng_unref(node); 690 } 691 } 692 693 /************************************************************************ 694 Hook routines 695 696 Names are not optional. Hooks are always connected, except for a 697 brief moment within these routines. 698 699 ************************************************************************/ 700 701 /* 702 * Remove a hook reference 703 */ 704 void 705 ng_unref_hook(hook_p hook) 706 { 707 crit_enter(); 708 if (--hook->refs == 0) 709 FREE(hook, M_NETGRAPH); 710 crit_exit(); 711 } 712 713 /* 714 * Add an unconnected hook to a node. Only used internally. 715 */ 716 static int 717 ng_add_hook(node_p node, const char *name, hook_p *hookp) 718 { 719 hook_p hook; 720 int error = 0; 721 722 /* Check that the given name is good */ 723 if (name == NULL) { 724 TRAP_ERROR; 725 return (EINVAL); 726 } 727 if (ng_findhook(node, name) != NULL) { 728 TRAP_ERROR; 729 return (EEXIST); 730 } 731 732 /* Allocate the hook and link it up */ 733 MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_NOWAIT | M_ZERO); 734 if (hook == NULL) { 735 TRAP_ERROR; 736 return (ENOMEM); 737 } 738 hook->refs = 1; 739 hook->flags = HK_INVALID; 740 hook->node = node; 741 node->refs++; /* each hook counts as a reference */ 742 743 /* Check if the node type code has something to say about it */ 744 if (node->type->newhook != NULL) 745 if ((error = (*node->type->newhook)(node, hook, name)) != 0) 746 goto fail; 747 748 /* 749 * The 'type' agrees so far, so go ahead and link it in. 750 * We'll ask again later when we actually connect the hooks. 751 */ 752 LIST_INSERT_HEAD(&node->hooks, hook, hooks); 753 node->numhooks++; 754 755 /* Set hook name */ 756 MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_NOWAIT); 757 if (hook->name == NULL) { 758 error = ENOMEM; 759 LIST_REMOVE(hook, hooks); 760 node->numhooks--; 761 fail: 762 hook->node = NULL; 763 ng_unref(node); 764 ng_unref_hook(hook); /* this frees the hook */ 765 return (error); 766 } 767 strcpy(hook->name, name); 768 if (hookp) 769 *hookp = hook; 770 return (error); 771 } 772 773 /* 774 * Connect a pair of hooks. Only used internally. 775 */ 776 static int 777 ng_connect(hook_p hook1, hook_p hook2) 778 { 779 int error; 780 781 hook1->peer = hook2; 782 hook2->peer = hook1; 783 784 /* Give each node the opportunity to veto the impending connection */ 785 if (hook1->node->type->connect) { 786 if ((error = (*hook1->node->type->connect) (hook1))) { 787 ng_destroy_hook(hook1); /* also zaps hook2 */ 788 return (error); 789 } 790 } 791 if (hook2->node->type->connect) { 792 if ((error = (*hook2->node->type->connect) (hook2))) { 793 ng_destroy_hook(hook2); /* also zaps hook1 */ 794 return (error); 795 } 796 } 797 hook1->flags &= ~HK_INVALID; 798 hook2->flags &= ~HK_INVALID; 799 return (0); 800 } 801 802 /* 803 * Find a hook 804 * 805 * Node types may supply their own optimized routines for finding 806 * hooks. If none is supplied, we just do a linear search. 807 */ 808 hook_p 809 ng_findhook(node_p node, const char *name) 810 { 811 hook_p hook; 812 813 if (node->type->findhook != NULL) 814 return (*node->type->findhook)(node, name); 815 LIST_FOREACH(hook, &node->hooks, hooks) { 816 if (hook->name != NULL 817 && strcmp(hook->name, name) == 0 818 && (hook->flags & HK_INVALID) == 0) 819 return (hook); 820 } 821 return (NULL); 822 } 823 824 /* 825 * Destroy a hook 826 * 827 * As hooks are always attached, this really destroys two hooks. 828 * The one given, and the one attached to it. Disconnect the hooks 829 * from each other first. 830 */ 831 void 832 ng_destroy_hook(hook_p hook) 833 { 834 hook_p peer = hook->peer; 835 836 hook->flags |= HK_INVALID; /* as soon as possible */ 837 if (peer) { 838 peer->flags |= HK_INVALID; /* as soon as possible */ 839 hook->peer = NULL; 840 peer->peer = NULL; 841 ng_disconnect_hook(peer); 842 } 843 ng_disconnect_hook(hook); 844 } 845 846 /* 847 * Notify the node of the hook's demise. This may result in more actions 848 * (e.g. shutdown) but we don't do that ourselves and don't know what 849 * happens there. If there is no appropriate handler, then just remove it 850 * (and decrement the reference count of it's node which in turn might 851 * make something happen). 852 */ 853 static void 854 ng_disconnect_hook(hook_p hook) 855 { 856 node_p node = hook->node; 857 858 /* 859 * Remove the hook from the node's list to avoid possible recursion 860 * in case the disconnection results in node shutdown. 861 */ 862 LIST_REMOVE(hook, hooks); 863 node->numhooks--; 864 if (node->type->disconnect) { 865 /* 866 * The type handler may elect to destroy the peer so don't 867 * trust its existance after this point. 868 */ 869 (*node->type->disconnect) (hook); 870 } 871 ng_unref(node); /* might be the last reference */ 872 if (hook->name) 873 FREE(hook->name, M_NETGRAPH); 874 hook->node = NULL; /* may still be referenced elsewhere */ 875 ng_unref_hook(hook); 876 } 877 878 /* 879 * Take two hooks on a node and merge the connection so that the given node 880 * is effectively bypassed. 881 */ 882 int 883 ng_bypass(hook_p hook1, hook_p hook2) 884 { 885 if (hook1->node != hook2->node) 886 return (EINVAL); 887 hook1->peer->peer = hook2->peer; 888 hook2->peer->peer = hook1->peer; 889 890 /* XXX If we ever cache methods on hooks update them as well */ 891 hook1->peer = NULL; 892 hook2->peer = NULL; 893 ng_destroy_hook(hook1); 894 ng_destroy_hook(hook2); 895 return (0); 896 } 897 898 /* 899 * Install a new netgraph type 900 */ 901 int 902 ng_newtype(struct ng_type *tp) 903 { 904 const size_t namelen = strlen(tp->name); 905 906 /* Check version and type name fields */ 907 if (tp->version != NG_VERSION || namelen == 0 || namelen >= NG_TYPESIZ) { 908 TRAP_ERROR; 909 return (EINVAL); 910 } 911 912 /* Check for name collision */ 913 if (ng_findtype(tp->name) != NULL) { 914 TRAP_ERROR; 915 return (EEXIST); 916 } 917 918 /* Link in new type */ 919 LIST_INSERT_HEAD(&typelist, tp, types); 920 tp->refs = 1; /* first ref is linked list */ 921 return (0); 922 } 923 924 /* 925 * Look for a type of the name given 926 */ 927 struct ng_type * 928 ng_findtype(const char *typename) 929 { 930 struct ng_type *type; 931 932 LIST_FOREACH(type, &typelist, types) { 933 if (strcmp(type->name, typename) == 0) 934 break; 935 } 936 return (type); 937 } 938 939 940 /************************************************************************ 941 Composite routines 942 ************************************************************************/ 943 944 /* 945 * Make a peer and connect. The order is arranged to minimise 946 * the work needed to back out in case of error. 947 */ 948 int 949 ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 950 { 951 node_p node2; 952 hook_p hook; 953 hook_p hook2; 954 int error; 955 956 if ((error = ng_add_hook(node, name, &hook))) 957 return (error); 958 959 /* make sure we have the module needed */ 960 if (ng_findtype(type) == NULL) { 961 /* Not found, try to load it as a loadable module */ 962 error = ng_load_module(type); 963 if (error != 0) { 964 kprintf("required netgraph module ng_%s not loaded\n", 965 type); 966 return (error); 967 } 968 } 969 if ((error = ng_make_node(type, &node2))) { 970 ng_destroy_hook(hook); 971 return (error); 972 } 973 if ((error = ng_add_hook(node2, name2, &hook2))) { 974 ng_rmnode(node2); 975 ng_destroy_hook(hook); 976 return (error); 977 } 978 979 /* 980 * Actually link the two hooks together.. on failure they are 981 * destroyed so we don't have to do that here. 982 */ 983 if ((error = ng_connect(hook, hook2))) 984 ng_rmnode(node2); 985 return (error); 986 } 987 988 /* 989 * Connect two nodes using the specified hooks 990 */ 991 int 992 ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2) 993 { 994 int error; 995 hook_p hook; 996 hook_p hook2; 997 998 if ((error = ng_add_hook(node, name, &hook))) 999 return (error); 1000 if ((error = ng_add_hook(node2, name2, &hook2))) { 1001 ng_destroy_hook(hook); 1002 return (error); 1003 } 1004 return (ng_connect(hook, hook2)); 1005 } 1006 1007 /* 1008 * Parse and verify a string of the form: <NODE:><PATH> 1009 * 1010 * Such a string can refer to a specific node or a specific hook 1011 * on a specific node, depending on how you look at it. In the 1012 * latter case, the PATH component must not end in a dot. 1013 * 1014 * Both <NODE:> and <PATH> are optional. The <PATH> is a string 1015 * of hook names separated by dots. This breaks out the original 1016 * string, setting *nodep to "NODE" (or NULL if none) and *pathp 1017 * to "PATH" (or NULL if degenerate). Also, *hookp will point to 1018 * the final hook component of <PATH>, if any, otherwise NULL. 1019 * 1020 * This returns -1 if the path is malformed. The char ** are optional. 1021 */ 1022 1023 int 1024 ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 1025 { 1026 char *node, *path, *hook; 1027 int k; 1028 1029 /* 1030 * Extract absolute NODE, if any 1031 */ 1032 for (path = addr; *path && *path != ':'; path++); 1033 if (*path) { 1034 node = addr; /* Here's the NODE */ 1035 *path++ = '\0'; /* Here's the PATH */ 1036 1037 /* Node name must not be empty */ 1038 if (!*node) 1039 return -1; 1040 1041 /* A name of "." is OK; otherwise '.' not allowed */ 1042 if (strcmp(node, ".") != 0) { 1043 for (k = 0; node[k]; k++) 1044 if (node[k] == '.') 1045 return -1; 1046 } 1047 } else { 1048 node = NULL; /* No absolute NODE */ 1049 path = addr; /* Here's the PATH */ 1050 } 1051 1052 /* Snoop for illegal characters in PATH */ 1053 for (k = 0; path[k]; k++) 1054 if (path[k] == ':') 1055 return -1; 1056 1057 /* Check for no repeated dots in PATH */ 1058 for (k = 0; path[k]; k++) 1059 if (path[k] == '.' && path[k + 1] == '.') 1060 return -1; 1061 1062 /* Remove extra (degenerate) dots from beginning or end of PATH */ 1063 if (path[0] == '.') 1064 path++; 1065 if (*path && path[strlen(path) - 1] == '.') 1066 path[strlen(path) - 1] = 0; 1067 1068 /* If PATH has a dot, then we're not talking about a hook */ 1069 if (*path) { 1070 for (hook = path, k = 0; path[k]; k++) 1071 if (path[k] == '.') { 1072 hook = NULL; 1073 break; 1074 } 1075 } else 1076 path = hook = NULL; 1077 1078 /* Done */ 1079 if (nodep) 1080 *nodep = node; 1081 if (pathp) 1082 *pathp = path; 1083 if (hookp) 1084 *hookp = hook; 1085 return (0); 1086 } 1087 1088 /* 1089 * Given a path, which may be absolute or relative, and a starting node, 1090 * return the destination node. Compute the "return address" if desired. 1091 */ 1092 int 1093 ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp) 1094 { 1095 const node_p start = here; 1096 char fullpath[NG_PATHSIZ]; 1097 char *nodename, *path, pbuf[2]; 1098 node_p node; 1099 char *cp; 1100 1101 /* Initialize */ 1102 if (rtnp) 1103 *rtnp = NULL; 1104 if (destp == NULL) 1105 return EINVAL; 1106 *destp = NULL; 1107 1108 /* Make a writable copy of address for ng_path_parse() */ 1109 strncpy(fullpath, address, sizeof(fullpath) - 1); 1110 fullpath[sizeof(fullpath) - 1] = '\0'; 1111 1112 /* Parse out node and sequence of hooks */ 1113 if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 1114 TRAP_ERROR; 1115 return EINVAL; 1116 } 1117 if (path == NULL) { 1118 pbuf[0] = '.'; /* Needs to be writable */ 1119 pbuf[1] = '\0'; 1120 path = pbuf; 1121 } 1122 1123 /* For an absolute address, jump to the starting node */ 1124 if (nodename) { 1125 node = ng_findname(here, nodename); 1126 if (node == NULL) { 1127 TRAP_ERROR; 1128 return (ENOENT); 1129 } 1130 } else 1131 node = here; 1132 1133 /* Now follow the sequence of hooks */ 1134 for (cp = path; node != NULL && *cp != '\0'; ) { 1135 hook_p hook; 1136 char *segment; 1137 1138 /* 1139 * Break out the next path segment. Replace the dot we just 1140 * found with a NUL; "cp" points to the next segment (or the 1141 * NUL at the end). 1142 */ 1143 for (segment = cp; *cp != '\0'; cp++) { 1144 if (*cp == '.') { 1145 *cp++ = '\0'; 1146 break; 1147 } 1148 } 1149 1150 /* Empty segment */ 1151 if (*segment == '\0') 1152 continue; 1153 1154 /* We have a segment, so look for a hook by that name */ 1155 hook = ng_findhook(node, segment); 1156 1157 /* Can't get there from here... */ 1158 if (hook == NULL 1159 || hook->peer == NULL 1160 || (hook->flags & HK_INVALID) != 0) { 1161 TRAP_ERROR; 1162 return (ENOENT); 1163 } 1164 1165 /* Hop on over to the next node */ 1166 node = hook->peer->node; 1167 } 1168 1169 /* If node somehow missing, fail here (probably this is not needed) */ 1170 if (node == NULL) { 1171 TRAP_ERROR; 1172 return (ENXIO); 1173 } 1174 1175 /* Now compute return address, i.e., the path to the sender */ 1176 if (rtnp != NULL) { 1177 MALLOC(*rtnp, char *, NG_NODESIZ + 1, M_NETGRAPH, M_NOWAIT); 1178 if (*rtnp == NULL) { 1179 TRAP_ERROR; 1180 return (ENOMEM); 1181 } 1182 if (start->name != NULL) 1183 ksprintf(*rtnp, "%s:", start->name); 1184 else 1185 ksprintf(*rtnp, "[%x]:", ng_node2ID(start)); 1186 } 1187 1188 /* Done */ 1189 *destp = node; 1190 return (0); 1191 } 1192 1193 /* 1194 * Call the appropriate message handler for the object. 1195 * It is up to the message handler to free the message. 1196 * If it's a generic message, handle it generically, otherwise 1197 * call the type's message handler (if it exists) 1198 * XXX (race). Remember that a queued message may reference a node 1199 * or hook that has just been invalidated. It will exist 1200 * as the queue code is holding a reference, but.. 1201 */ 1202 1203 #define CALL_MSG_HANDLER(error, node, msg, retaddr, resp) \ 1204 do { \ 1205 if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \ 1206 (error) = ng_generic_msg((node), (msg), \ 1207 (retaddr), (resp)); \ 1208 } else { \ 1209 if ((node)->type->rcvmsg != NULL) { \ 1210 (error) = (*(node)->type->rcvmsg)((node), \ 1211 (msg), (retaddr), (resp)); \ 1212 } else { \ 1213 TRAP_ERROR; \ 1214 FREE((msg), M_NETGRAPH); \ 1215 (error) = EINVAL; \ 1216 } \ 1217 } \ 1218 } while (0) 1219 1220 1221 /* 1222 * Send a control message to a node 1223 */ 1224 int 1225 ng_send_msg(node_p here, struct ng_mesg *msg, const char *address, 1226 struct ng_mesg **rptr) 1227 { 1228 node_p dest = NULL; 1229 char *retaddr = NULL; 1230 int error; 1231 1232 /* Find the target node */ 1233 error = ng_path2node(here, address, &dest, &retaddr); 1234 if (error) { 1235 FREE(msg, M_NETGRAPH); 1236 return error; 1237 } 1238 1239 /* Make sure the resp field is null before we start */ 1240 if (rptr != NULL) 1241 *rptr = NULL; 1242 1243 CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr); 1244 1245 /* Make sure that if there is a response, it has the RESP bit set */ 1246 if ((error == 0) && rptr && *rptr) 1247 (*rptr)->header.flags |= NGF_RESP; 1248 1249 /* 1250 * If we had a return address it is up to us to free it. They should 1251 * have taken a copy if they needed to make a delayed response. 1252 */ 1253 if (retaddr) 1254 FREE(retaddr, M_NETGRAPH); 1255 return (error); 1256 } 1257 1258 /* 1259 * Implement the 'generic' control messages 1260 */ 1261 static int 1262 ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr, 1263 struct ng_mesg **resp) 1264 { 1265 int error = 0; 1266 1267 if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 1268 TRAP_ERROR; 1269 FREE(msg, M_NETGRAPH); 1270 return (EINVAL); 1271 } 1272 switch (msg->header.cmd) { 1273 case NGM_SHUTDOWN: 1274 ng_rmnode(here); 1275 break; 1276 case NGM_MKPEER: 1277 { 1278 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 1279 1280 if (msg->header.arglen != sizeof(*mkp)) { 1281 TRAP_ERROR; 1282 return (EINVAL); 1283 } 1284 mkp->type[sizeof(mkp->type) - 1] = '\0'; 1285 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 1286 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 1287 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 1288 break; 1289 } 1290 case NGM_CONNECT: 1291 { 1292 struct ngm_connect *const con = 1293 (struct ngm_connect *) msg->data; 1294 node_p node2; 1295 1296 if (msg->header.arglen != sizeof(*con)) { 1297 TRAP_ERROR; 1298 return (EINVAL); 1299 } 1300 con->path[sizeof(con->path) - 1] = '\0'; 1301 con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 1302 con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 1303 error = ng_path2node(here, con->path, &node2, NULL); 1304 if (error) 1305 break; 1306 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook); 1307 break; 1308 } 1309 case NGM_NAME: 1310 { 1311 struct ngm_name *const nam = (struct ngm_name *) msg->data; 1312 1313 if (msg->header.arglen != sizeof(*nam)) { 1314 TRAP_ERROR; 1315 return (EINVAL); 1316 } 1317 nam->name[sizeof(nam->name) - 1] = '\0'; 1318 error = ng_name_node(here, nam->name); 1319 break; 1320 } 1321 case NGM_RMHOOK: 1322 { 1323 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 1324 hook_p hook; 1325 1326 if (msg->header.arglen != sizeof(*rmh)) { 1327 TRAP_ERROR; 1328 return (EINVAL); 1329 } 1330 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 1331 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 1332 ng_destroy_hook(hook); 1333 break; 1334 } 1335 case NGM_NODEINFO: 1336 { 1337 struct nodeinfo *ni; 1338 struct ng_mesg *rp; 1339 1340 /* Get response struct */ 1341 if (resp == NULL) { 1342 error = EINVAL; 1343 break; 1344 } 1345 NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT); 1346 if (rp == NULL) { 1347 error = ENOMEM; 1348 break; 1349 } 1350 1351 /* Fill in node info */ 1352 ni = (struct nodeinfo *) rp->data; 1353 if (here->name != NULL) 1354 strlcpy(ni->name, here->name, NG_NODESIZ); 1355 strlcpy(ni->type, here->type->name, NG_TYPESIZ); 1356 ni->id = ng_node2ID(here); 1357 ni->hooks = here->numhooks; 1358 *resp = rp; 1359 break; 1360 } 1361 case NGM_LISTHOOKS: 1362 { 1363 const int nhooks = here->numhooks; 1364 struct hooklist *hl; 1365 struct nodeinfo *ni; 1366 struct ng_mesg *rp; 1367 hook_p hook; 1368 1369 /* Get response struct */ 1370 if (resp == NULL) { 1371 error = EINVAL; 1372 break; 1373 } 1374 NG_MKRESPONSE(rp, msg, sizeof(*hl) 1375 + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 1376 if (rp == NULL) { 1377 error = ENOMEM; 1378 break; 1379 } 1380 hl = (struct hooklist *) rp->data; 1381 ni = &hl->nodeinfo; 1382 1383 /* Fill in node info */ 1384 if (here->name) 1385 strlcpy(ni->name, here->name, NG_NODESIZ); 1386 strlcpy(ni->type, here->type->name, NG_TYPESIZ); 1387 ni->id = ng_node2ID(here); 1388 1389 /* Cycle through the linked list of hooks */ 1390 ni->hooks = 0; 1391 LIST_FOREACH(hook, &here->hooks, hooks) { 1392 struct linkinfo *const link = &hl->link[ni->hooks]; 1393 1394 if (ni->hooks >= nhooks) { 1395 log(LOG_ERR, "%s: number of %s changed\n", 1396 __func__, "hooks"); 1397 break; 1398 } 1399 if ((hook->flags & HK_INVALID) != 0) 1400 continue; 1401 strlcpy(link->ourhook, hook->name, NG_HOOKSIZ); 1402 strlcpy(link->peerhook, hook->peer->name, NG_HOOKSIZ); 1403 if (hook->peer->node->name != NULL) 1404 strlcpy(link->nodeinfo.name, 1405 hook->peer->node->name, NG_NODESIZ); 1406 strlcpy(link->nodeinfo.type, 1407 hook->peer->node->type->name, NG_TYPESIZ); 1408 link->nodeinfo.id = ng_node2ID(hook->peer->node); 1409 link->nodeinfo.hooks = hook->peer->node->numhooks; 1410 ni->hooks++; 1411 } 1412 *resp = rp; 1413 break; 1414 } 1415 1416 case NGM_LISTNAMES: 1417 case NGM_LISTNODES: 1418 { 1419 const int unnamed = (msg->header.cmd == NGM_LISTNODES); 1420 struct namelist *nl; 1421 struct ng_mesg *rp; 1422 node_p node; 1423 int num = 0; 1424 1425 if (resp == NULL) { 1426 error = EINVAL; 1427 break; 1428 } 1429 1430 /* Count number of nodes */ 1431 LIST_FOREACH(node, &nodelist, nodes) { 1432 if ((node->flags & NG_INVALID) == 0 1433 && (unnamed || node->name != NULL)) 1434 num++; 1435 } 1436 1437 /* Get response struct */ 1438 if (resp == NULL) { 1439 error = EINVAL; 1440 break; 1441 } 1442 NG_MKRESPONSE(rp, msg, sizeof(*nl) 1443 + (num * sizeof(struct nodeinfo)), M_NOWAIT); 1444 if (rp == NULL) { 1445 error = ENOMEM; 1446 break; 1447 } 1448 nl = (struct namelist *) rp->data; 1449 1450 /* Cycle through the linked list of nodes */ 1451 nl->numnames = 0; 1452 LIST_FOREACH(node, &nodelist, nodes) { 1453 struct nodeinfo *const np = &nl->nodeinfo[nl->numnames]; 1454 1455 if (nl->numnames >= num) { 1456 log(LOG_ERR, "%s: number of %s changed\n", 1457 __func__, "nodes"); 1458 break; 1459 } 1460 if ((node->flags & NG_INVALID) != 0) 1461 continue; 1462 if (!unnamed && node->name == NULL) 1463 continue; 1464 if (node->name != NULL) 1465 strlcpy(np->name, node->name, NG_NODESIZ); 1466 strlcpy(np->type, node->type->name, NG_TYPESIZ); 1467 np->id = ng_node2ID(node); 1468 np->hooks = node->numhooks; 1469 nl->numnames++; 1470 } 1471 *resp = rp; 1472 break; 1473 } 1474 1475 case NGM_LISTTYPES: 1476 { 1477 struct typelist *tl; 1478 struct ng_mesg *rp; 1479 struct ng_type *type; 1480 int num = 0; 1481 1482 if (resp == NULL) { 1483 error = EINVAL; 1484 break; 1485 } 1486 1487 /* Count number of types */ 1488 LIST_FOREACH(type, &typelist, types) 1489 num++; 1490 1491 /* Get response struct */ 1492 if (resp == NULL) { 1493 error = EINVAL; 1494 break; 1495 } 1496 NG_MKRESPONSE(rp, msg, sizeof(*tl) 1497 + (num * sizeof(struct typeinfo)), M_NOWAIT); 1498 if (rp == NULL) { 1499 error = ENOMEM; 1500 break; 1501 } 1502 tl = (struct typelist *) rp->data; 1503 1504 /* Cycle through the linked list of types */ 1505 tl->numtypes = 0; 1506 LIST_FOREACH(type, &typelist, types) { 1507 struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 1508 1509 if (tl->numtypes >= num) { 1510 log(LOG_ERR, "%s: number of %s changed\n", 1511 __func__, "types"); 1512 break; 1513 } 1514 strlcpy(tp->type_name, type->name, NG_TYPESIZ); 1515 tp->numnodes = type->refs - 1; /* don't count list */ 1516 tl->numtypes++; 1517 } 1518 *resp = rp; 1519 break; 1520 } 1521 1522 case NGM_BINARY2ASCII: 1523 { 1524 int bufSize = 20 * 1024; /* XXX hard coded constant */ 1525 const struct ng_parse_type *argstype; 1526 const struct ng_cmdlist *c; 1527 struct ng_mesg *rp, *binary, *ascii; 1528 1529 /* Data area must contain a valid netgraph message */ 1530 binary = (struct ng_mesg *)msg->data; 1531 if (msg->header.arglen < sizeof(struct ng_mesg) 1532 || msg->header.arglen - sizeof(struct ng_mesg) 1533 < binary->header.arglen) { 1534 error = EINVAL; 1535 break; 1536 } 1537 1538 /* Get a response message with lots of room */ 1539 NG_MKRESPONSE(rp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 1540 if (rp == NULL) { 1541 error = ENOMEM; 1542 break; 1543 } 1544 ascii = (struct ng_mesg *)rp->data; 1545 1546 /* Copy binary message header to response message payload */ 1547 bcopy(binary, ascii, sizeof(*binary)); 1548 1549 /* Find command by matching typecookie and command number */ 1550 for (c = here->type->cmdlist; 1551 c != NULL && c->name != NULL; c++) { 1552 if (binary->header.typecookie == c->cookie 1553 && binary->header.cmd == c->cmd) 1554 break; 1555 } 1556 if (c == NULL || c->name == NULL) { 1557 for (c = ng_generic_cmds; c->name != NULL; c++) { 1558 if (binary->header.typecookie == c->cookie 1559 && binary->header.cmd == c->cmd) 1560 break; 1561 } 1562 if (c->name == NULL) { 1563 FREE(rp, M_NETGRAPH); 1564 error = ENOSYS; 1565 break; 1566 } 1567 } 1568 1569 /* Convert command name to ASCII */ 1570 ksnprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 1571 "%s", c->name); 1572 1573 /* Convert command arguments to ASCII */ 1574 argstype = (binary->header.flags & NGF_RESP) ? 1575 c->respType : c->mesgType; 1576 if (argstype == NULL) 1577 *ascii->data = '\0'; 1578 else { 1579 if ((error = ng_unparse(argstype, 1580 (u_char *)binary->data, 1581 ascii->data, bufSize)) != 0) { 1582 FREE(rp, M_NETGRAPH); 1583 break; 1584 } 1585 } 1586 1587 /* Return the result as struct ng_mesg plus ASCII string */ 1588 bufSize = strlen(ascii->data) + 1; 1589 ascii->header.arglen = bufSize; 1590 rp->header.arglen = sizeof(*ascii) + bufSize; 1591 *resp = rp; 1592 break; 1593 } 1594 1595 case NGM_ASCII2BINARY: 1596 { 1597 int bufSize = 2000; /* XXX hard coded constant */ 1598 const struct ng_cmdlist *c; 1599 const struct ng_parse_type *argstype; 1600 struct ng_mesg *rp, *ascii, *binary; 1601 int off = 0; 1602 1603 /* Data area must contain at least a struct ng_mesg + '\0' */ 1604 ascii = (struct ng_mesg *)msg->data; 1605 if (msg->header.arglen < sizeof(*ascii) + 1 1606 || ascii->header.arglen < 1 1607 || msg->header.arglen 1608 < sizeof(*ascii) + ascii->header.arglen) { 1609 error = EINVAL; 1610 break; 1611 } 1612 ascii->data[ascii->header.arglen - 1] = '\0'; 1613 1614 /* Get a response message with lots of room */ 1615 NG_MKRESPONSE(rp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 1616 if (rp == NULL) { 1617 error = ENOMEM; 1618 break; 1619 } 1620 binary = (struct ng_mesg *)rp->data; 1621 1622 /* Copy ASCII message header to response message payload */ 1623 bcopy(ascii, binary, sizeof(*ascii)); 1624 1625 /* Find command by matching ASCII command string */ 1626 for (c = here->type->cmdlist; 1627 c != NULL && c->name != NULL; c++) { 1628 if (strcmp(ascii->header.cmdstr, c->name) == 0) 1629 break; 1630 } 1631 if (c == NULL || c->name == NULL) { 1632 for (c = ng_generic_cmds; c->name != NULL; c++) { 1633 if (strcmp(ascii->header.cmdstr, c->name) == 0) 1634 break; 1635 } 1636 if (c->name == NULL) { 1637 FREE(rp, M_NETGRAPH); 1638 error = ENOSYS; 1639 break; 1640 } 1641 } 1642 1643 /* Convert command name to binary */ 1644 binary->header.cmd = c->cmd; 1645 binary->header.typecookie = c->cookie; 1646 1647 /* Convert command arguments to binary */ 1648 argstype = (binary->header.flags & NGF_RESP) ? 1649 c->respType : c->mesgType; 1650 if (argstype == NULL) 1651 bufSize = 0; 1652 else { 1653 if ((error = ng_parse(argstype, ascii->data, 1654 &off, (u_char *)binary->data, &bufSize)) != 0) { 1655 FREE(rp, M_NETGRAPH); 1656 break; 1657 } 1658 } 1659 1660 /* Return the result */ 1661 binary->header.arglen = bufSize; 1662 rp->header.arglen = sizeof(*binary) + bufSize; 1663 *resp = rp; 1664 break; 1665 } 1666 1667 case NGM_TEXT_CONFIG: 1668 case NGM_TEXT_STATUS: 1669 /* 1670 * This one is tricky as it passes the command down to the 1671 * actual node, even though it is a generic type command. 1672 * This means we must assume that the msg is already freed 1673 * when control passes back to us. 1674 */ 1675 if (resp == NULL) { 1676 error = EINVAL; 1677 break; 1678 } 1679 if (here->type->rcvmsg != NULL) 1680 return((*here->type->rcvmsg)(here, msg, retaddr, resp)); 1681 /* Fall through if rcvmsg not supported */ 1682 default: 1683 TRAP_ERROR; 1684 error = EINVAL; 1685 } 1686 FREE(msg, M_NETGRAPH); 1687 return (error); 1688 } 1689 1690 /* 1691 * Send a data packet to a node. If the recipient has no 1692 * 'receive data' method, then silently discard the packet. 1693 */ 1694 int 1695 ng_send_data(hook_p hook, struct mbuf *m, meta_p meta) 1696 { 1697 int (*rcvdata)(hook_p, struct mbuf *, meta_p); 1698 int error; 1699 1700 CHECK_DATA_MBUF(m); 1701 if (hook && (hook->flags & HK_INVALID) == 0) { 1702 rcvdata = hook->peer->node->type->rcvdata; 1703 if (rcvdata != NULL) 1704 error = (*rcvdata)(hook->peer, m, meta); 1705 else { 1706 error = 0; 1707 NG_FREE_DATA(m, meta); 1708 } 1709 } else { 1710 TRAP_ERROR; 1711 error = ENOTCONN; 1712 NG_FREE_DATA(m, meta); 1713 } 1714 return (error); 1715 } 1716 1717 /* 1718 * Send a queued data packet to a node. If the recipient has no 1719 * 'receive queued data' method, then try the 'receive data' method above. 1720 */ 1721 int 1722 ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta) 1723 { 1724 int (*rcvdataq)(hook_p, struct mbuf *, meta_p); 1725 int error; 1726 1727 CHECK_DATA_MBUF(m); 1728 if (hook && (hook->flags & HK_INVALID) == 0) { 1729 rcvdataq = hook->peer->node->type->rcvdataq; 1730 if (rcvdataq != NULL) 1731 error = (*rcvdataq)(hook->peer, m, meta); 1732 else { 1733 error = ng_send_data(hook, m, meta); 1734 } 1735 } else { 1736 TRAP_ERROR; 1737 error = ENOTCONN; 1738 NG_FREE_DATA(m, meta); 1739 } 1740 return (error); 1741 } 1742 1743 /* 1744 * Copy a 'meta'. 1745 * 1746 * Returns new meta, or NULL if original meta is NULL or ENOMEM. 1747 */ 1748 meta_p 1749 ng_copy_meta(meta_p meta) 1750 { 1751 meta_p meta2; 1752 1753 if (meta == NULL) 1754 return (NULL); 1755 MALLOC(meta2, meta_p, meta->used_len, M_NETGRAPH, M_NOWAIT); 1756 if (meta2 == NULL) 1757 return (NULL); 1758 meta2->allocated_len = meta->used_len; 1759 bcopy(meta, meta2, meta->used_len); 1760 return (meta2); 1761 } 1762 1763 /************************************************************************ 1764 Module routines 1765 ************************************************************************/ 1766 1767 /* 1768 * Handle the loading/unloading of a netgraph node type module 1769 */ 1770 int 1771 ng_mod_event(module_t mod, int event, void *data) 1772 { 1773 struct ng_type *const type = data; 1774 int error = 0; 1775 1776 switch (event) { 1777 case MOD_LOAD: 1778 1779 /* Register new netgraph node type */ 1780 crit_enter(); 1781 if ((error = ng_newtype(type)) != 0) { 1782 crit_exit(); 1783 break; 1784 } 1785 1786 /* Call type specific code */ 1787 if (type->mod_event != NULL) 1788 if ((error = (*type->mod_event)(mod, event, data))) { 1789 type->refs--; /* undo it */ 1790 LIST_REMOVE(type, types); 1791 } 1792 crit_exit(); 1793 break; 1794 1795 case MOD_UNLOAD: 1796 crit_enter(); 1797 if (type->refs > 1) { /* make sure no nodes exist! */ 1798 error = EBUSY; 1799 } else { 1800 if (type->refs == 0) { 1801 /* failed load, nothing to undo */ 1802 crit_exit(); 1803 break; 1804 } 1805 if (type->mod_event != NULL) { /* check with type */ 1806 error = (*type->mod_event)(mod, event, data); 1807 if (error != 0) { /* type refuses.. */ 1808 crit_exit(); 1809 break; 1810 } 1811 } 1812 LIST_REMOVE(type, types); 1813 } 1814 crit_exit(); 1815 break; 1816 1817 default: 1818 if (type->mod_event != NULL) 1819 error = (*type->mod_event)(mod, event, data); 1820 else 1821 error = 0; /* XXX ? */ 1822 break; 1823 } 1824 return (error); 1825 } 1826 1827 /* 1828 * Handle loading and unloading for this code. 1829 * The only thing we need to link into is the NETISR strucure. 1830 */ 1831 static int 1832 ngb_mod_event(module_t mod, int event, void *data) 1833 { 1834 int error = 0; 1835 1836 switch (event) { 1837 case MOD_LOAD: 1838 /* Register line discipline */ 1839 crit_enter(); 1840 error = ng_load_module("ksocket"); 1841 if (error != 0) { 1842 crit_exit(); 1843 break; 1844 } 1845 netisr_register(NETISR_NETGRAPH, cpu0_portfn, 1846 pktinfo_portfn_notsupp, ngintr, 1847 NETISR_FLAG_NOTMPSAFE); 1848 error = 0; 1849 crit_exit(); 1850 break; 1851 case MOD_UNLOAD: 1852 ng_unload_module("ksocket"); 1853 /* You cant unload it because an interface may be using it. */ 1854 error = EBUSY; 1855 break; 1856 default: 1857 error = EOPNOTSUPP; 1858 break; 1859 } 1860 return (error); 1861 } 1862 1863 static moduledata_t netgraph_mod = { 1864 "netgraph", 1865 ngb_mod_event, 1866 (NULL) 1867 }; 1868 DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1869 SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 1870 SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 1871 SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 1872 1873 /************************************************************************ 1874 Queueing routines 1875 ************************************************************************/ 1876 1877 /* The structure for queueing across ISR switches */ 1878 struct ng_queue_entry { 1879 u_long flags; 1880 struct ng_queue_entry *next; 1881 union { 1882 struct { 1883 hook_p da_hook; /* target hook */ 1884 struct mbuf *da_m; 1885 meta_p da_meta; 1886 } data; 1887 struct { 1888 struct ng_mesg *msg_msg; 1889 node_p msg_node; 1890 void *msg_retaddr; 1891 } msg; 1892 } body; 1893 }; 1894 #define NGQF_DATA 0x01 /* the queue element is data */ 1895 #define NGQF_MESG 0x02 /* the queue element is a message */ 1896 1897 static struct ng_queue_entry *ngqbase; /* items to be unqueued */ 1898 static struct ng_queue_entry *ngqlast; /* last item queued */ 1899 static const int ngqroom = 256; /* max items to queue */ 1900 static int ngqsize; /* number of items in queue */ 1901 1902 static struct ng_queue_entry *ngqfree; /* free ones */ 1903 static const int ngqfreemax = 256;/* cache at most this many */ 1904 static int ngqfreesize; /* number of cached entries */ 1905 1906 /* 1907 * Get a queue entry 1908 */ 1909 static struct ng_queue_entry * 1910 ng_getqblk(void) 1911 { 1912 struct ng_queue_entry *q; 1913 1914 /* Could be guarding against tty ints or whatever */ 1915 crit_enter(); 1916 1917 /* Try get a cached queue block, or else allocate a new one */ 1918 if ((q = ngqfree) == NULL) { 1919 crit_exit(); 1920 if (ngqsize < ngqroom) { /* don't worry about races */ 1921 MALLOC(q, struct ng_queue_entry *, 1922 sizeof(*q), M_NETGRAPH, M_NOWAIT); 1923 } 1924 } else { 1925 ngqfree = q->next; 1926 ngqfreesize--; 1927 crit_exit(); 1928 } 1929 return (q); 1930 } 1931 1932 /* 1933 * Release a queue entry 1934 */ 1935 #define RETURN_QBLK(q) \ 1936 do { \ 1937 if (ngqfreesize < ngqfreemax) { /* don't worry about races */ \ 1938 crit_enter(); \ 1939 (q)->next = ngqfree; \ 1940 ngqfree = (q); \ 1941 ngqfreesize++; \ 1942 crit_exit(); \ 1943 } else { \ 1944 FREE((q), M_NETGRAPH); \ 1945 } \ 1946 } while (0) 1947 1948 /* 1949 * Running at a raised (but we don't know which) processor priority level, 1950 * put the data onto a queue to be picked up by another PPL (probably splnet) 1951 */ 1952 int 1953 ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta) 1954 { 1955 struct ng_queue_entry *q; 1956 1957 if (hook == NULL) { 1958 NG_FREE_DATA(m, meta); 1959 return (0); 1960 } 1961 if ((q = ng_getqblk()) == NULL) { 1962 NG_FREE_DATA(m, meta); 1963 return (ENOBUFS); 1964 } 1965 1966 /* Fill out the contents */ 1967 q->flags = NGQF_DATA; 1968 q->next = NULL; 1969 q->body.data.da_hook = hook; 1970 q->body.data.da_m = m; 1971 q->body.data.da_meta = meta; 1972 crit_enter(); /* protect refs and queue */ 1973 hook->refs++; /* don't let it go away while on the queue */ 1974 1975 /* Put it on the queue */ 1976 if (ngqbase) { 1977 ngqlast->next = q; 1978 } else { 1979 ngqbase = q; 1980 } 1981 ngqlast = q; 1982 ngqsize++; 1983 crit_exit(); 1984 1985 /* Schedule software interrupt to handle it later */ 1986 schednetisr(NETISR_NETGRAPH); 1987 return (0); 1988 } 1989 1990 /* 1991 * Running at a raised (but we don't know which) processor priority level, 1992 * put the msg onto a queue to be picked up by another PPL (probably splnet) 1993 */ 1994 int 1995 ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address) 1996 { 1997 struct ng_queue_entry *q; 1998 node_p dest = NULL; 1999 char *retaddr = NULL; 2000 int error; 2001 2002 /* Find the target node. */ 2003 error = ng_path2node(here, address, &dest, &retaddr); 2004 if (error) { 2005 FREE(msg, M_NETGRAPH); 2006 return (error); 2007 } 2008 if ((q = ng_getqblk()) == NULL) { 2009 FREE(msg, M_NETGRAPH); 2010 if (retaddr) 2011 FREE(retaddr, M_NETGRAPH); 2012 return (ENOBUFS); 2013 } 2014 2015 /* Fill out the contents */ 2016 q->flags = NGQF_MESG; 2017 q->next = NULL; 2018 q->body.msg.msg_node = dest; 2019 q->body.msg.msg_msg = msg; 2020 q->body.msg.msg_retaddr = retaddr; 2021 crit_enter(); /* protect refs and queue */ 2022 dest->refs++; /* don't let it go away while on the queue */ 2023 2024 /* Put it on the queue */ 2025 if (ngqbase) { 2026 ngqlast->next = q; 2027 } else { 2028 ngqbase = q; 2029 } 2030 ngqlast = q; 2031 ngqsize++; 2032 crit_exit(); 2033 2034 /* Schedule software interrupt to handle it later */ 2035 schednetisr(NETISR_NETGRAPH); 2036 return (0); 2037 } 2038 2039 /* 2040 * Pick an item off the queue, process it, and dispose of the queue entry. 2041 */ 2042 static void 2043 ngintr(struct netmsg *pmsg) 2044 { 2045 hook_p hook; 2046 struct mbuf *m; 2047 struct ng_queue_entry *ngq; 2048 meta_p meta; 2049 void *retaddr; 2050 struct ng_mesg *msg; 2051 node_p node; 2052 int error = 0; 2053 2054 /* 2055 * Packets are never sent to this netisr so the message must always 2056 * be replied. Interlock processing and notification by replying 2057 * the message first. 2058 */ 2059 lwkt_replymsg(&pmsg->nm_lmsg, 0); 2060 2061 while (1) { 2062 crit_enter(); 2063 if ((ngq = ngqbase)) { 2064 ngqbase = ngq->next; 2065 ngqsize--; 2066 } 2067 crit_exit(); 2068 if (ngq == NULL) 2069 goto out; 2070 switch (ngq->flags) { 2071 case NGQF_DATA: 2072 hook = ngq->body.data.da_hook; 2073 m = ngq->body.data.da_m; 2074 meta = ngq->body.data.da_meta; 2075 RETURN_QBLK(ngq); 2076 NG_SEND_DATAQ(error, hook, m, meta); 2077 ng_unref_hook(hook); 2078 break; 2079 case NGQF_MESG: 2080 node = ngq->body.msg.msg_node; 2081 msg = ngq->body.msg.msg_msg; 2082 retaddr = ngq->body.msg.msg_retaddr; 2083 RETURN_QBLK(ngq); 2084 if (node->flags & NG_INVALID) { 2085 FREE(msg, M_NETGRAPH); 2086 } else { 2087 CALL_MSG_HANDLER(error, node, msg, 2088 retaddr, NULL); 2089 } 2090 ng_unref(node); 2091 if (retaddr) 2092 FREE(retaddr, M_NETGRAPH); 2093 break; 2094 default: 2095 RETURN_QBLK(ngq); 2096 } 2097 } 2098 out: 2099 ; 2100 } 2101 2102 2103