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