ng_base.c revision 53403
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@whistle.com> 38 * Archie Cobbs <archie@whistle.com> 39 * 40 * $FreeBSD: head/sys/netgraph/ng_base.c 53403 1999-11-19 05:43:33Z archie $ 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/socketvar.h> 58#include <sys/ctype.h> 59#include <machine/limits.h> 60 61#include <net/netisr.h> 62 63#include <netgraph/ng_message.h> 64#include <netgraph/netgraph.h> 65 66/* List of all nodes */ 67static LIST_HEAD(, ng_node) nodelist; 68 69/* List of installed types */ 70static LIST_HEAD(, ng_type) typelist; 71 72/* Hash releted definitions */ 73#define ID_HASH_SIZE 32 /* most systems wont need even this many */ 74static LIST_HEAD(, ng_node) ID_hash[ID_HASH_SIZE]; 75/* Don't nead to initialise them because it's a LIST */ 76 77/* Internal functions */ 78static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 79static int ng_connect(hook_p hook1, hook_p hook2); 80static void ng_disconnect_hook(hook_p hook); 81static int ng_generic_msg(node_p here, struct ng_mesg *msg, 82 const char *retaddr, struct ng_mesg ** resp); 83static ng_ID_t ng_decodeidname(const char *name); 84static int ngb_mod_event(module_t mod, int event, void *data); 85static void ngintr(void); 86 87/* Our own netgraph malloc type */ 88MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 89 90/* Set this to Debugger("X") to catch all errors as they occur */ 91#ifndef TRAP_ERROR 92#define TRAP_ERROR 93#endif 94 95static ng_ID_t nextID = 1; 96 97#ifdef INVARIANTS 98#define CHECK_DATA_MBUF(m) do { \ 99 struct mbuf *n; \ 100 int total; \ 101 \ 102 if (((m)->m_flags & M_PKTHDR) == 0) \ 103 panic("%s: !PKTHDR", __FUNCTION__); \ 104 for (total = 0, n = (m); n != NULL; n = n->m_next) \ 105 total += n->m_len; \ 106 if ((m)->m_pkthdr.len != total) { \ 107 panic("%s: %d != %d", \ 108 __FUNCTION__, (m)->m_pkthdr.len, total); \ 109 } \ 110 } while (0) 111#else 112#define CHECK_DATA_MBUF(m) 113#endif 114 115 116/************************************************************************ 117 Node routines 118************************************************************************/ 119 120/* 121 * Instantiate a node of the requested type 122 */ 123int 124ng_make_node(const char *typename, node_p *nodepp) 125{ 126 struct ng_type *type; 127 128 /* Check that the type makes sense */ 129 if (typename == NULL) { 130 TRAP_ERROR; 131 return (EINVAL); 132 } 133 134 /* Locate the node type */ 135 if ((type = ng_findtype(typename)) == NULL) { 136 char *path, filename[NG_TYPELEN + 4]; 137 linker_file_t lf; 138 int error; 139 140 /* Not found, try to load it as a loadable module */ 141 snprintf(filename, sizeof(filename), "ng_%s.ko", typename); 142 if ((path = linker_search_path(filename)) == NULL) 143 return (ENXIO); 144 error = linker_load_file(path, &lf); 145 FREE(path, M_LINKER); 146 if (error != 0) 147 return (error); 148 lf->userrefs++; /* pretend loaded by the syscall */ 149 150 /* Try again, as now the type should have linked itself in */ 151 if ((type = ng_findtype(typename)) == NULL) 152 return (ENXIO); 153 } 154 155 /* Call the constructor */ 156 if (type->constructor != NULL) 157 return ((*type->constructor)(nodepp)); 158 else 159 return (ng_make_node_common(type, nodepp)); 160} 161 162/* 163 * Generic node creation. Called by node constructors. 164 * The returned node has a reference count of 1. 165 */ 166int 167ng_make_node_common(struct ng_type *type, node_p *nodepp) 168{ 169 node_p node; 170 171 /* Require the node type to have been already installed */ 172 if (ng_findtype(type->name) == NULL) { 173 TRAP_ERROR; 174 return (EINVAL); 175 } 176 177 /* Make a node and try attach it to the type */ 178 MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_WAITOK); 179 if (node == NULL) { 180 TRAP_ERROR; 181 return (ENOMEM); 182 } 183 bzero(node, sizeof(*node)); 184 node->type = type; 185 node->refs++; /* note reference */ 186 type->refs++; 187 188 /* Link us into the node linked list */ 189 LIST_INSERT_HEAD(&nodelist, node, nodes); 190 191 /* Initialize hook list for new node */ 192 LIST_INIT(&node->hooks); 193 194 /* get an ID and put us in the hash chain */ 195 node->ID = nextID++; /* 137 per second for 1 year before wrap */ 196 LIST_INSERT_HEAD(&ID_hash[node->ID % ID_HASH_SIZE], node, idnodes); 197 198 /* Done */ 199 *nodepp = node; 200 return (0); 201} 202 203/* 204 * Forceably start the shutdown process on a node. Either call 205 * it's shutdown method, or do the default shutdown if there is 206 * no type-specific method. 207 * 208 * Persistent nodes must have a type-specific method which 209 * resets the NG_INVALID flag. 210 */ 211void 212ng_rmnode(node_p node) 213{ 214 /* Check if it's already shutting down */ 215 if ((node->flags & NG_INVALID) != 0) 216 return; 217 218 /* Add an extra reference so it doesn't go away during this */ 219 node->refs++; 220 221 /* Mark it invalid so any newcomers know not to try use it */ 222 node->flags |= NG_INVALID; 223 224 /* Ask the type if it has anything to do in this case */ 225 if (node->type && node->type->shutdown) 226 (*node->type->shutdown)(node); 227 else { /* do the default thing */ 228 ng_unname(node); 229 ng_cutlinks(node); 230 ng_unref(node); 231 } 232 233 /* Remove extra reference, possibly the last */ 234 ng_unref(node); 235} 236 237/* 238 * Called by the destructor to remove any STANDARD external references 239 */ 240void 241ng_cutlinks(node_p node) 242{ 243 hook_p hook; 244 245 /* Make sure that this is set to stop infinite loops */ 246 node->flags |= NG_INVALID; 247 248 /* If we have sleepers, wake them up; they'll see NG_INVALID */ 249 if (node->sleepers) 250 wakeup(node); 251 252 /* Notify all remaining connected nodes to disconnect */ 253 while ((hook = LIST_FIRST(&node->hooks)) != NULL) 254 ng_destroy_hook(hook); 255} 256 257/* 258 * Remove a reference to the node, possibly the last 259 */ 260void 261ng_unref(node_p node) 262{ 263 if (--node->refs <= 0) { 264 node->type->refs--; 265 LIST_REMOVE(node, nodes); 266 LIST_REMOVE(node, idnodes); 267 FREE(node, M_NETGRAPH); 268 } 269} 270 271/* 272 * Wait for a node to come ready. Returns a node with a reference count; 273 * don't forget to drop it when we are done with it using ng_release_node(). 274 */ 275int 276ng_wait_node(node_p node, char *msg) 277{ 278 int s, error = 0; 279 280 if (msg == NULL) 281 msg = "netgraph"; 282 s = splnet(); 283 node->sleepers++; 284 node->refs++; /* the sleeping process counts as a reference */ 285 while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY) 286 error = tsleep(node, (PZERO + 1) | PCATCH, msg, 0); 287 node->sleepers--; 288 if (node->flags & NG_INVALID) { 289 TRAP_ERROR; 290 error = ENXIO; 291 } else { 292 KASSERT(node->refs > 1, 293 ("%s: refs=%d", __FUNCTION__, node->refs)); 294 node->flags |= NG_BUSY; 295 } 296 splx(s); 297 298 /* Release the reference we had on it */ 299 if (error != 0) 300 ng_unref(node); 301 return error; 302} 303 304/* 305 * Release a node acquired via ng_wait_node() 306 */ 307void 308ng_release_node(node_p node) 309{ 310 /* Declare that we don't want it */ 311 node->flags &= ~NG_BUSY; 312 313 /* If we have sleepers, then wake them up */ 314 if (node->sleepers) 315 wakeup(node); 316 317 /* We also have a reference.. drop it too */ 318 ng_unref(node); 319} 320 321/************************************************************************ 322 Node ID handling 323************************************************************************/ 324static node_p 325ng_ID2node(ng_ID_t ID) 326{ 327 node_p np; 328 LIST_FOREACH(np, &ID_hash[ID % ID_HASH_SIZE], idnodes) { 329 if (np->ID == ID) 330 break; 331 } 332 return(np); 333} 334 335ng_ID_t 336ng_node2ID(node_p node) 337{ 338 return (node->ID); 339} 340 341/************************************************************************ 342 Node name handling 343************************************************************************/ 344 345/* 346 * Assign a node a name. Once assigned, the name cannot be changed. 347 */ 348int 349ng_name_node(node_p node, const char *name) 350{ 351 int i; 352 353 /* Check the name is valid */ 354 for (i = 0; i < NG_NODELEN + 1; i++) { 355 if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 356 break; 357 } 358 if (i == 0 || name[i] != '\0') { 359 TRAP_ERROR; 360 return (EINVAL); 361 } 362 if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 363 TRAP_ERROR; 364 return (EINVAL); 365 } 366 367 /* Check the node isn't already named */ 368 if (node->name != NULL) { 369 TRAP_ERROR; 370 return (EISCONN); 371 } 372 373 /* Check the name isn't already being used */ 374 if (ng_findname(node, name) != NULL) { 375 TRAP_ERROR; 376 return (EADDRINUSE); 377 } 378 379 /* Allocate space and copy it */ 380 MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK); 381 if (node->name == NULL) { 382 TRAP_ERROR; 383 return (ENOMEM); 384 } 385 strcpy(node->name, name); 386 387 /* The name counts as a reference */ 388 node->refs++; 389 return (0); 390} 391 392/* 393 * Find a node by absolute name. The name should NOT end with ':' 394 * The name "." means "this node" and "[xxx]" means "the node 395 * with ID (ie, at address) xxx". 396 * 397 * Returns the node if found, else NULL. 398 */ 399node_p 400ng_findname(node_p this, const char *name) 401{ 402 node_p node; 403 ng_ID_t temp; 404 405 /* "." means "this node" */ 406 if (strcmp(name, ".") == 0) 407 return(this); 408 409 /* Check for name-by-ID */ 410 if ((temp = ng_decodeidname(name)) != 0) { 411 return (ng_ID2node(temp)); 412 } 413 414 /* Find node by name */ 415 LIST_FOREACH(node, &nodelist, nodes) { 416 if (node->name != NULL && strcmp(node->name, name) == 0) 417 break; 418 } 419 return (node); 420} 421 422/* 423 * Decode a ID name, eg. "[f03034de]". Returns 0 if the 424 * string is not valid, otherwise returns the value. 425 */ 426static ng_ID_t 427ng_decodeidname(const char *name) 428{ 429 const int len = strlen(name); 430 const char *eptr; 431 u_long val; 432 433 /* Check for proper length, brackets, no leading junk */ 434 if (len < 3 || name[0] != '[' || name[len - 1] != ']' 435 || !isxdigit(name[1])) 436 return (0); 437 438 /* Decode number */ 439 val = strtoul(name + 1, &eptr, 16); 440 if (eptr - name != len - 1 || val == ULONG_MAX || val == 0) 441 return ((ng_ID_t)0); 442 return (ng_ID_t)val; 443} 444 445/* 446 * Remove a name from a node. This should only be called 447 * when shutting down and removing the node. 448 */ 449void 450ng_unname(node_p node) 451{ 452 if (node->name) { 453 FREE(node->name, M_NETGRAPH); 454 node->name = NULL; 455 ng_unref(node); 456 } 457} 458 459/************************************************************************ 460 Hook routines 461 462 Names are not optional. Hooks are always connected, except for a 463 brief moment within these routines. 464 465************************************************************************/ 466 467/* 468 * Remove a hook reference 469 */ 470static void 471ng_unref_hook(hook_p hook) 472{ 473 if (--hook->refs == 0) 474 FREE(hook, M_NETGRAPH); 475} 476 477/* 478 * Add an unconnected hook to a node. Only used internally. 479 */ 480static int 481ng_add_hook(node_p node, const char *name, hook_p *hookp) 482{ 483 hook_p hook; 484 int error = 0; 485 486 /* Check that the given name is good */ 487 if (name == NULL) { 488 TRAP_ERROR; 489 return (EINVAL); 490 } 491 LIST_FOREACH(hook, &node->hooks, hooks) { 492 if (strcmp(hook->name, name) == 0) { 493 TRAP_ERROR; 494 return (EEXIST); 495 } 496 } 497 498 /* Allocate the hook and link it up */ 499 MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_WAITOK); 500 if (hook == NULL) { 501 TRAP_ERROR; 502 return (ENOMEM); 503 } 504 bzero(hook, sizeof(*hook)); 505 hook->refs = 1; 506 hook->flags = HK_INVALID; 507 hook->node = node; 508 node->refs++; /* each hook counts as a reference */ 509 510 /* Check if the node type code has something to say about it */ 511 if (node->type->newhook != NULL) 512 if ((error = (*node->type->newhook)(node, hook, name)) != 0) 513 goto fail; 514 515 /* 516 * The 'type' agrees so far, so go ahead and link it in. 517 * We'll ask again later when we actually connect the hooks. 518 */ 519 LIST_INSERT_HEAD(&node->hooks, hook, hooks); 520 node->numhooks++; 521 522 /* Set hook name */ 523 MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK); 524 if (hook->name == NULL) { 525 error = ENOMEM; 526 LIST_REMOVE(hook, hooks); 527 node->numhooks--; 528fail: 529 hook->node = NULL; 530 ng_unref(node); 531 ng_unref_hook(hook); /* this frees the hook */ 532 return (error); 533 } 534 strcpy(hook->name, name); 535 if (hookp) 536 *hookp = hook; 537 return (error); 538} 539 540/* 541 * Connect a pair of hooks. Only used internally. 542 */ 543static int 544ng_connect(hook_p hook1, hook_p hook2) 545{ 546 int error; 547 548 hook1->peer = hook2; 549 hook2->peer = hook1; 550 551 /* Give each node the opportunity to veto the impending connection */ 552 if (hook1->node->type->connect) { 553 if ((error = (*hook1->node->type->connect) (hook1))) { 554 ng_destroy_hook(hook1); /* also zaps hook2 */ 555 return (error); 556 } 557 } 558 if (hook2->node->type->connect) { 559 if ((error = (*hook2->node->type->connect) (hook2))) { 560 ng_destroy_hook(hook2); /* also zaps hook1 */ 561 return (error); 562 } 563 } 564 hook1->flags &= ~HK_INVALID; 565 hook2->flags &= ~HK_INVALID; 566 return (0); 567} 568 569/* 570 * Destroy a hook 571 * 572 * As hooks are always attached, this really destroys two hooks. 573 * The one given, and the one attached to it. Disconnect the hooks 574 * from each other first. 575 */ 576void 577ng_destroy_hook(hook_p hook) 578{ 579 hook_p peer = hook->peer; 580 581 hook->flags |= HK_INVALID; /* as soon as possible */ 582 if (peer) { 583 peer->flags |= HK_INVALID; /* as soon as possible */ 584 hook->peer = NULL; 585 peer->peer = NULL; 586 ng_disconnect_hook(peer); 587 } 588 ng_disconnect_hook(hook); 589} 590 591/* 592 * Notify the node of the hook's demise. This may result in more actions 593 * (e.g. shutdown) but we don't do that ourselves and don't know what 594 * happens there. If there is no appropriate handler, then just remove it 595 * (and decrement the reference count of it's node which in turn might 596 * make something happen). 597 */ 598static void 599ng_disconnect_hook(hook_p hook) 600{ 601 node_p node = hook->node; 602 603 /* 604 * Remove the hook from the node's list to avoid possible recursion 605 * in case the disconnection results in node shutdown. 606 */ 607 LIST_REMOVE(hook, hooks); 608 node->numhooks--; 609 if (node->type->disconnect) { 610 /* 611 * The type handler may elect to destroy the peer so don't 612 * trust its existance after this point. 613 */ 614 (*node->type->disconnect) (hook); 615 } 616 ng_unref(node); /* might be the last reference */ 617 if (hook->name) 618 FREE(hook->name, M_NETGRAPH); 619 hook->node = NULL; /* may still be referenced elsewhere */ 620 ng_unref_hook(hook); 621} 622 623/* 624 * Take two hooks on a node and merge the connection so that the given node 625 * is effectively bypassed. 626 */ 627int 628ng_bypass(hook_p hook1, hook_p hook2) 629{ 630 if (hook1->node != hook2->node) 631 return (EINVAL); 632 hook1->peer->peer = hook2->peer; 633 hook2->peer->peer = hook1->peer; 634 635 /* XXX If we ever cache methods on hooks update them as well */ 636 hook1->peer = NULL; 637 hook2->peer = NULL; 638 ng_destroy_hook(hook1); 639 ng_destroy_hook(hook2); 640 return (0); 641} 642 643/* 644 * Install a new netgraph type 645 */ 646int 647ng_newtype(struct ng_type *tp) 648{ 649 const size_t namelen = strlen(tp->name); 650 651 /* Check version and type name fields */ 652 if (tp->version != NG_VERSION || namelen == 0 || namelen > NG_TYPELEN) { 653 TRAP_ERROR; 654 return (EINVAL); 655 } 656 657 /* Check for name collision */ 658 if (ng_findtype(tp->name) != NULL) { 659 TRAP_ERROR; 660 return (EEXIST); 661 } 662 663 /* Link in new type */ 664 LIST_INSERT_HEAD(&typelist, tp, types); 665 tp->refs = 0; 666 return (0); 667} 668 669/* 670 * Look for a type of the name given 671 */ 672struct ng_type * 673ng_findtype(const char *typename) 674{ 675 struct ng_type *type; 676 677 LIST_FOREACH(type, &typelist, types) { 678 if (strcmp(type->name, typename) == 0) 679 break; 680 } 681 return (type); 682} 683 684 685/************************************************************************ 686 Composite routines 687************************************************************************/ 688 689/* 690 * Make a peer and connect. The order is arranged to minimise 691 * the work needed to back out in case of error. 692 */ 693int 694ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 695{ 696 node_p node2; 697 hook_p hook; 698 hook_p hook2; 699 int error; 700 701 if ((error = ng_add_hook(node, name, &hook))) 702 return (error); 703 if ((error = ng_make_node(type, &node2))) { 704 ng_destroy_hook(hook); 705 return (error); 706 } 707 if ((error = ng_add_hook(node2, name2, &hook2))) { 708 ng_rmnode(node2); 709 ng_destroy_hook(hook); 710 return (error); 711 } 712 713 /* 714 * Actually link the two hooks together.. on failure they are 715 * destroyed so we don't have to do that here. 716 */ 717 if ((error = ng_connect(hook, hook2))) 718 ng_rmnode(node2); 719 return (error); 720} 721 722/* 723 * Connect two nodes using the specified hooks 724 */ 725int 726ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2) 727{ 728 int error; 729 hook_p hook; 730 hook_p hook2; 731 732 if ((error = ng_add_hook(node, name, &hook))) 733 return (error); 734 if ((error = ng_add_hook(node2, name2, &hook2))) { 735 ng_destroy_hook(hook); 736 return (error); 737 } 738 return (ng_connect(hook, hook2)); 739} 740 741/* 742 * Parse and verify a string of the form: <NODE:><PATH> 743 * 744 * Such a string can refer to a specific node or a specific hook 745 * on a specific node, depending on how you look at it. In the 746 * latter case, the PATH component must not end in a dot. 747 * 748 * Both <NODE:> and <PATH> are optional. The <PATH> is a string 749 * of hook names separated by dots. This breaks out the original 750 * string, setting *nodep to "NODE" (or NULL if none) and *pathp 751 * to "PATH" (or NULL if degenerate). Also, *hookp will point to 752 * the final hook component of <PATH>, if any, otherwise NULL. 753 * 754 * This returns -1 if the path is malformed. The char ** are optional. 755 */ 756 757int 758ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 759{ 760 char *node, *path, *hook; 761 int k; 762 763 /* 764 * Extract absolute NODE, if any 765 */ 766 for (path = addr; *path && *path != ':'; path++); 767 if (*path) { 768 node = addr; /* Here's the NODE */ 769 *path++ = '\0'; /* Here's the PATH */ 770 771 /* Node name must not be empty */ 772 if (!*node) 773 return -1; 774 775 /* A name of "." is OK; otherwise '.' not allowed */ 776 if (strcmp(node, ".") != 0) { 777 for (k = 0; node[k]; k++) 778 if (node[k] == '.') 779 return -1; 780 } 781 } else { 782 node = NULL; /* No absolute NODE */ 783 path = addr; /* Here's the PATH */ 784 } 785 786 /* Snoop for illegal characters in PATH */ 787 for (k = 0; path[k]; k++) 788 if (path[k] == ':') 789 return -1; 790 791 /* Check for no repeated dots in PATH */ 792 for (k = 0; path[k]; k++) 793 if (path[k] == '.' && path[k + 1] == '.') 794 return -1; 795 796 /* Remove extra (degenerate) dots from beginning or end of PATH */ 797 if (path[0] == '.') 798 path++; 799 if (*path && path[strlen(path) - 1] == '.') 800 path[strlen(path) - 1] = 0; 801 802 /* If PATH has a dot, then we're not talking about a hook */ 803 if (*path) { 804 for (hook = path, k = 0; path[k]; k++) 805 if (path[k] == '.') { 806 hook = NULL; 807 break; 808 } 809 } else 810 path = hook = NULL; 811 812 /* Done */ 813 if (nodep) 814 *nodep = node; 815 if (pathp) 816 *pathp = path; 817 if (hookp) 818 *hookp = hook; 819 return (0); 820} 821 822/* 823 * Given a path, which may be absolute or relative, and a starting node, 824 * return the destination node. Compute the "return address" if desired. 825 */ 826int 827ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp) 828{ 829 const node_p start = here; 830 char fullpath[NG_PATHLEN + 1]; 831 char *nodename, *path, pbuf[2]; 832 node_p node; 833 char *cp; 834 835 /* Initialize */ 836 if (rtnp) 837 *rtnp = NULL; 838 if (destp == NULL) 839 return EINVAL; 840 *destp = NULL; 841 842 /* Make a writable copy of address for ng_path_parse() */ 843 strncpy(fullpath, address, sizeof(fullpath) - 1); 844 fullpath[sizeof(fullpath) - 1] = '\0'; 845 846 /* Parse out node and sequence of hooks */ 847 if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 848 TRAP_ERROR; 849 return EINVAL; 850 } 851 if (path == NULL) { 852 pbuf[0] = '.'; /* Needs to be writable */ 853 pbuf[1] = '\0'; 854 path = pbuf; 855 } 856 857 /* For an absolute address, jump to the starting node */ 858 if (nodename) { 859 node = ng_findname(here, nodename); 860 if (node == NULL) { 861 TRAP_ERROR; 862 return (ENOENT); 863 } 864 } else 865 node = here; 866 867 /* Now follow the sequence of hooks */ 868 for (cp = path; node != NULL && *cp != '\0'; ) { 869 hook_p hook; 870 char *segment; 871 872 /* 873 * Break out the next path segment. Replace the dot we just 874 * found with a NUL; "cp" points to the next segment (or the 875 * NUL at the end). 876 */ 877 for (segment = cp; *cp != '\0'; cp++) { 878 if (*cp == '.') { 879 *cp++ = '\0'; 880 break; 881 } 882 } 883 884 /* Empty segment */ 885 if (*segment == '\0') 886 continue; 887 888 /* We have a segment, so look for a hook by that name */ 889 LIST_FOREACH(hook, &node->hooks, hooks) { 890 if (hook->name && strcmp(hook->name, segment) == 0) 891 break; 892 } 893 894 /* Can't get there from here... */ 895 if (hook == NULL 896 || hook->peer == NULL 897 || (hook->flags & HK_INVALID) != 0) { 898 TRAP_ERROR; 899 return (ENOENT); 900 } 901 902 /* Hop on over to the next node */ 903 node = hook->peer->node; 904 } 905 906 /* If node somehow missing, fail here (probably this is not needed) */ 907 if (node == NULL) { 908 TRAP_ERROR; 909 return (ENXIO); 910 } 911 912 /* Now compute return address, i.e., the path to the sender */ 913 if (rtnp != NULL) { 914 MALLOC(*rtnp, char *, NG_NODELEN + 2, M_NETGRAPH, M_WAITOK); 915 if (*rtnp == NULL) { 916 TRAP_ERROR; 917 return (ENOMEM); 918 } 919 if (start->name != NULL) 920 sprintf(*rtnp, "%s:", start->name); 921 else 922 sprintf(*rtnp, "[%x]:", ng_node2ID(start)); 923 } 924 925 /* Done */ 926 *destp = node; 927 return (0); 928} 929 930/* 931 * Call the appropriate message handler for the object. 932 * It is up to the message handler to free the message. 933 * If it's a generic message, handle it generically, otherwise 934 * call the type's message handler (if it exists) 935 */ 936 937#define CALL_MSG_HANDLER(error, node, msg, retaddr, resp) \ 938do { \ 939 if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \ 940 (error) = ng_generic_msg((node), (msg), \ 941 (retaddr), (resp)); \ 942 } else { \ 943 if ((node)->type->rcvmsg != NULL) { \ 944 (error) = (*(node)->type->rcvmsg)((node), \ 945 (msg), (retaddr), (resp)); \ 946 } else { \ 947 TRAP_ERROR; \ 948 FREE((msg), M_NETGRAPH); \ 949 (error) = EINVAL; \ 950 } \ 951 } \ 952} while (0) 953 954 955/* 956 * Send a control message to a node 957 */ 958int 959ng_send_msg(node_p here, struct ng_mesg *msg, const char *address, 960 struct ng_mesg **rptr) 961{ 962 node_p dest = NULL; 963 char *retaddr = NULL; 964 int error; 965 966 /* Find the target node */ 967 error = ng_path2node(here, address, &dest, &retaddr); 968 if (error) { 969 FREE(msg, M_NETGRAPH); 970 return error; 971 } 972 973 /* Make sure the resp field is null before we start */ 974 if (rptr != NULL) 975 *rptr = NULL; 976 977 CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr); 978 979 /* Make sure that if there is a response, it has the RESP bit set */ 980 if ((error == 0) && rptr && *rptr) 981 (*rptr)->header.flags |= NGF_RESP; 982 983 /* 984 * If we had a return address it is up to us to free it. They should 985 * have taken a copy if they needed to make a delayed response. 986 */ 987 if (retaddr) 988 FREE(retaddr, M_NETGRAPH); 989 return (error); 990} 991 992/* 993 * Implement the 'generic' control messages 994 */ 995static int 996ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr, 997 struct ng_mesg **resp) 998{ 999 int error = 0; 1000 1001 if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 1002 TRAP_ERROR; 1003 FREE(msg, M_NETGRAPH); 1004 return (EINVAL); 1005 } 1006 switch (msg->header.cmd) { 1007 case NGM_SHUTDOWN: 1008 ng_rmnode(here); 1009 break; 1010 case NGM_MKPEER: 1011 { 1012 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 1013 1014 if (msg->header.arglen != sizeof(*mkp)) { 1015 TRAP_ERROR; 1016 return (EINVAL); 1017 } 1018 mkp->type[sizeof(mkp->type) - 1] = '\0'; 1019 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 1020 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 1021 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 1022 break; 1023 } 1024 case NGM_CONNECT: 1025 { 1026 struct ngm_connect *const con = 1027 (struct ngm_connect *) msg->data; 1028 node_p node2; 1029 1030 if (msg->header.arglen != sizeof(*con)) { 1031 TRAP_ERROR; 1032 return (EINVAL); 1033 } 1034 con->path[sizeof(con->path) - 1] = '\0'; 1035 con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 1036 con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 1037 error = ng_path2node(here, con->path, &node2, NULL); 1038 if (error) 1039 break; 1040 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook); 1041 break; 1042 } 1043 case NGM_NAME: 1044 { 1045 struct ngm_name *const nam = (struct ngm_name *) msg->data; 1046 1047 if (msg->header.arglen != sizeof(*nam)) { 1048 TRAP_ERROR; 1049 return (EINVAL); 1050 } 1051 nam->name[sizeof(nam->name) - 1] = '\0'; 1052 error = ng_name_node(here, nam->name); 1053 break; 1054 } 1055 case NGM_RMHOOK: 1056 { 1057 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 1058 hook_p hook; 1059 1060 if (msg->header.arglen != sizeof(*rmh)) { 1061 TRAP_ERROR; 1062 return (EINVAL); 1063 } 1064 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 1065 LIST_FOREACH(hook, &here->hooks, hooks) { 1066 if (hook->name && strcmp(hook->name, rmh->ourhook) == 0) 1067 break; 1068 } 1069 if (hook) 1070 ng_destroy_hook(hook); 1071 break; 1072 } 1073 case NGM_NODEINFO: 1074 { 1075 struct nodeinfo *ni; 1076 struct ng_mesg *rp; 1077 1078 /* Get response struct */ 1079 if (resp == NULL) { 1080 error = EINVAL; 1081 break; 1082 } 1083 NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT); 1084 if (rp == NULL) { 1085 error = ENOMEM; 1086 break; 1087 } 1088 1089 /* Fill in node info */ 1090 ni = (struct nodeinfo *) rp->data; 1091 if (here->name != NULL) 1092 strncpy(ni->name, here->name, NG_NODELEN); 1093 strncpy(ni->type, here->type->name, NG_TYPELEN); 1094 ni->id = ng_node2ID(here); 1095 ni->hooks = here->numhooks; 1096 *resp = rp; 1097 break; 1098 } 1099 case NGM_LISTHOOKS: 1100 { 1101 const int nhooks = here->numhooks; 1102 struct hooklist *hl; 1103 struct nodeinfo *ni; 1104 struct ng_mesg *rp; 1105 hook_p hook; 1106 1107 /* Get response struct */ 1108 if (resp == NULL) { 1109 error = EINVAL; 1110 break; 1111 } 1112 NG_MKRESPONSE(rp, msg, sizeof(*hl) 1113 + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 1114 if (rp == NULL) { 1115 error = ENOMEM; 1116 break; 1117 } 1118 hl = (struct hooklist *) rp->data; 1119 ni = &hl->nodeinfo; 1120 1121 /* Fill in node info */ 1122 if (here->name) 1123 strncpy(ni->name, here->name, NG_NODELEN); 1124 strncpy(ni->type, here->type->name, NG_TYPELEN); 1125 ni->id = ng_node2ID(here); 1126 1127 /* Cycle through the linked list of hooks */ 1128 ni->hooks = 0; 1129 LIST_FOREACH(hook, &here->hooks, hooks) { 1130 struct linkinfo *const link = &hl->link[ni->hooks]; 1131 1132 if (ni->hooks >= nhooks) { 1133 log(LOG_ERR, "%s: number of %s changed\n", 1134 __FUNCTION__, "hooks"); 1135 break; 1136 } 1137 if ((hook->flags & HK_INVALID) != 0) 1138 continue; 1139 strncpy(link->ourhook, hook->name, NG_HOOKLEN); 1140 strncpy(link->peerhook, hook->peer->name, NG_HOOKLEN); 1141 if (hook->peer->node->name != NULL) 1142 strncpy(link->nodeinfo.name, 1143 hook->peer->node->name, NG_NODELEN); 1144 strncpy(link->nodeinfo.type, 1145 hook->peer->node->type->name, NG_TYPELEN); 1146 link->nodeinfo.id = ng_node2ID(hook->peer->node); 1147 link->nodeinfo.hooks = hook->peer->node->numhooks; 1148 ni->hooks++; 1149 } 1150 *resp = rp; 1151 break; 1152 } 1153 1154 case NGM_LISTNAMES: 1155 case NGM_LISTNODES: 1156 { 1157 const int unnamed = (msg->header.cmd == NGM_LISTNODES); 1158 struct namelist *nl; 1159 struct ng_mesg *rp; 1160 node_p node; 1161 int num = 0; 1162 1163 if (resp == NULL) { 1164 error = EINVAL; 1165 break; 1166 } 1167 1168 /* Count number of nodes */ 1169 LIST_FOREACH(node, &nodelist, nodes) { 1170 if (unnamed || node->name != NULL) 1171 num++; 1172 } 1173 1174 /* Get response struct */ 1175 if (resp == NULL) { 1176 error = EINVAL; 1177 break; 1178 } 1179 NG_MKRESPONSE(rp, msg, sizeof(*nl) 1180 + (num * sizeof(struct nodeinfo)), M_NOWAIT); 1181 if (rp == NULL) { 1182 error = ENOMEM; 1183 break; 1184 } 1185 nl = (struct namelist *) rp->data; 1186 1187 /* Cycle through the linked list of nodes */ 1188 nl->numnames = 0; 1189 LIST_FOREACH(node, &nodelist, nodes) { 1190 struct nodeinfo *const np = &nl->nodeinfo[nl->numnames]; 1191 1192 if (nl->numnames >= num) { 1193 log(LOG_ERR, "%s: number of %s changed\n", 1194 __FUNCTION__, "nodes"); 1195 break; 1196 } 1197 if ((node->flags & NG_INVALID) != 0) 1198 continue; 1199 if (!unnamed && node->name == NULL) 1200 continue; 1201 if (node->name != NULL) 1202 strncpy(np->name, node->name, NG_NODELEN); 1203 strncpy(np->type, node->type->name, NG_TYPELEN); 1204 np->id = ng_node2ID(node); 1205 np->hooks = node->numhooks; 1206 nl->numnames++; 1207 } 1208 *resp = rp; 1209 break; 1210 } 1211 1212 case NGM_LISTTYPES: 1213 { 1214 struct typelist *tl; 1215 struct ng_mesg *rp; 1216 struct ng_type *type; 1217 int num = 0; 1218 1219 if (resp == NULL) { 1220 error = EINVAL; 1221 break; 1222 } 1223 1224 /* Count number of types */ 1225 LIST_FOREACH(type, &typelist, types) 1226 num++; 1227 1228 /* Get response struct */ 1229 if (resp == NULL) { 1230 error = EINVAL; 1231 break; 1232 } 1233 NG_MKRESPONSE(rp, msg, sizeof(*tl) 1234 + (num * sizeof(struct typeinfo)), M_NOWAIT); 1235 if (rp == NULL) { 1236 error = ENOMEM; 1237 break; 1238 } 1239 tl = (struct typelist *) rp->data; 1240 1241 /* Cycle through the linked list of types */ 1242 tl->numtypes = 0; 1243 LIST_FOREACH(type, &typelist, types) { 1244 struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 1245 1246 if (tl->numtypes >= num) { 1247 log(LOG_ERR, "%s: number of %s changed\n", 1248 __FUNCTION__, "types"); 1249 break; 1250 } 1251 strncpy(tp->typename, type->name, NG_TYPELEN); 1252 tp->numnodes = type->refs; 1253 tl->numtypes++; 1254 } 1255 *resp = rp; 1256 break; 1257 } 1258 1259 case NGM_TEXT_STATUS: 1260 /* 1261 * This one is tricky as it passes the command down to the 1262 * actual node, even though it is a generic type command. 1263 * This means we must assume that the msg is already freed 1264 * when control passes back to us. 1265 */ 1266 if (resp == NULL) { 1267 error = EINVAL; 1268 break; 1269 } 1270 if (here->type->rcvmsg != NULL) 1271 return((*here->type->rcvmsg)(here, msg, retaddr, resp)); 1272 /* Fall through if rcvmsg not supported */ 1273 default: 1274 TRAP_ERROR; 1275 error = EINVAL; 1276 } 1277 FREE(msg, M_NETGRAPH); 1278 return (error); 1279} 1280 1281/* 1282 * Send a data packet to a node. If the recipient has no 1283 * 'receive data' method, then silently discard the packet. 1284 */ 1285int 1286ng_send_data(hook_p hook, struct mbuf *m, meta_p meta) 1287{ 1288 int (*rcvdata)(hook_p, struct mbuf *, meta_p); 1289 int error; 1290 1291 CHECK_DATA_MBUF(m); 1292 if (hook && (hook->flags & HK_INVALID) == 0) { 1293 rcvdata = hook->peer->node->type->rcvdata; 1294 if (rcvdata != NULL) 1295 error = (*rcvdata)(hook->peer, m, meta); 1296 else { 1297 error = 0; 1298 NG_FREE_DATA(m, meta); 1299 } 1300 } else { 1301 TRAP_ERROR; 1302 error = ENOTCONN; 1303 NG_FREE_DATA(m, meta); 1304 } 1305 return (error); 1306} 1307 1308/* 1309 * Send a queued data packet to a node. If the recipient has no 1310 * 'receive queued data' method, then try the 'receive data' method above. 1311 */ 1312int 1313ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta) 1314{ 1315 int (*rcvdataq)(hook_p, struct mbuf *, meta_p); 1316 int error; 1317 1318 CHECK_DATA_MBUF(m); 1319 if (hook && (hook->flags & HK_INVALID) == 0) { 1320 rcvdataq = hook->peer->node->type->rcvdataq; 1321 if (rcvdataq != NULL) 1322 error = (*rcvdataq)(hook->peer, m, meta); 1323 else { 1324 error = ng_send_data(hook, m, meta); 1325 } 1326 } else { 1327 TRAP_ERROR; 1328 error = ENOTCONN; 1329 NG_FREE_DATA(m, meta); 1330 } 1331 return (error); 1332} 1333 1334/************************************************************************ 1335 Module routines 1336************************************************************************/ 1337 1338/* 1339 * Handle the loading/unloading of a netgraph node type module 1340 */ 1341int 1342ng_mod_event(module_t mod, int event, void *data) 1343{ 1344 struct ng_type *const type = data; 1345 int s, error = 0; 1346 1347 switch (event) { 1348 case MOD_LOAD: 1349 1350 /* Register new netgraph node type */ 1351 s = splnet(); 1352 if ((error = ng_newtype(type)) != 0) { 1353 splx(s); 1354 break; 1355 } 1356 1357 /* Call type specific code */ 1358 if (type->mod_event != NULL) 1359 if ((error = (*type->mod_event)(mod, event, data)) != 0) 1360 LIST_REMOVE(type, types); 1361 splx(s); 1362 break; 1363 1364 case MOD_UNLOAD: 1365 s = splnet(); 1366 if (type->refs != 0) /* make sure no nodes exist! */ 1367 error = EBUSY; 1368 else { 1369 if (type->mod_event != NULL) { /* check with type */ 1370 error = (*type->mod_event)(mod, event, data); 1371 if (error != 0) { /* type refuses.. */ 1372 splx(s); 1373 break; 1374 } 1375 } 1376 LIST_REMOVE(type, types); 1377 } 1378 splx(s); 1379 break; 1380 1381 default: 1382 if (type->mod_event != NULL) 1383 error = (*type->mod_event)(mod, event, data); 1384 else 1385 error = 0; /* XXX ? */ 1386 break; 1387 } 1388 return (error); 1389} 1390 1391/* 1392 * Handle loading and unloading for this code. 1393 * The only thing we need to link into is the NETISR strucure. 1394 */ 1395static int 1396ngb_mod_event(module_t mod, int event, void *data) 1397{ 1398 int s, error = 0; 1399 1400 switch (event) { 1401 case MOD_LOAD: 1402 /* Register line discipline */ 1403 s = splimp(); 1404 error = register_netisr(NETISR_NETGRAPH, ngintr); 1405 splx(s); 1406 break; 1407 case MOD_UNLOAD: 1408 /* You cant unload it because an interface may be using it. */ 1409 error = EBUSY; 1410 break; 1411 default: 1412 error = EOPNOTSUPP; 1413 break; 1414 } 1415 return (error); 1416} 1417 1418static moduledata_t netgraph_mod = { 1419 "netgraph", 1420 ngb_mod_event, 1421 (NULL) 1422}; 1423DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 1424 1425/************************************************************************ 1426 Queueing routines 1427************************************************************************/ 1428 1429/* The structure for queueing across ISR switches */ 1430struct ng_queue_entry { 1431 u_long flags; 1432 struct ng_queue_entry *next; 1433 union { 1434 struct { 1435 hook_p da_hook; /* target hook */ 1436 struct mbuf *da_m; 1437 meta_p da_meta; 1438 } data; 1439 struct { 1440 struct ng_mesg *msg_msg; 1441 node_p msg_node; 1442 void *msg_retaddr; 1443 } msg; 1444 } body; 1445}; 1446#define NGQF_DATA 0x01 /* the queue element is data */ 1447#define NGQF_MESG 0x02 /* the queue element is a message */ 1448 1449static struct ng_queue_entry *ngqbase; /* items to be unqueued */ 1450static struct ng_queue_entry *ngqlast; /* last item queued */ 1451static const int ngqroom = 64; /* max items to queue */ 1452static int ngqsize; /* number of items in queue */ 1453 1454static struct ng_queue_entry *ngqfree; /* free ones */ 1455static const int ngqfreemax = 16;/* cache at most this many */ 1456static int ngqfreesize; /* number of cached entries */ 1457 1458/* 1459 * Get a queue entry 1460 */ 1461static struct ng_queue_entry * 1462ng_getqblk(void) 1463{ 1464 register struct ng_queue_entry *q; 1465 int s; 1466 1467 /* Could be guarding against tty ints or whatever */ 1468 s = splhigh(); 1469 1470 /* Try get a cached queue block, or else allocate a new one */ 1471 if ((q = ngqfree) == NULL) { 1472 splx(s); 1473 if (ngqsize < ngqroom) { /* don't worry about races */ 1474 MALLOC(q, struct ng_queue_entry *, 1475 sizeof(*q), M_NETGRAPH, M_NOWAIT); 1476 } 1477 } else { 1478 ngqfree = q->next; 1479 ngqfreesize--; 1480 splx(s); 1481 } 1482 return (q); 1483} 1484 1485/* 1486 * Release a queue entry 1487 */ 1488#define RETURN_QBLK(q) \ 1489do { \ 1490 int s; \ 1491 if (ngqfreesize < ngqfreemax) { /* don't worry about races */ \ 1492 s = splhigh(); \ 1493 (q)->next = ngqfree; \ 1494 ngqfree = (q); \ 1495 ngqfreesize++; \ 1496 splx(s); \ 1497 } else { \ 1498 FREE((q), M_NETGRAPH); \ 1499 } \ 1500} while (0) 1501 1502/* 1503 * Running at a raised (but we don't know which) processor priority level, 1504 * put the data onto a queue to be picked up by another PPL (probably splnet) 1505 */ 1506int 1507ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta) 1508{ 1509 struct ng_queue_entry *q; 1510 int s; 1511 1512 if (hook == NULL) { 1513 NG_FREE_DATA(m, meta); 1514 return (0); 1515 } 1516 if ((q = ng_getqblk()) == NULL) { 1517 NG_FREE_DATA(m, meta); 1518 return (ENOBUFS); 1519 } 1520 1521 /* Fill out the contents */ 1522 q->flags = NGQF_DATA; 1523 q->next = NULL; 1524 q->body.data.da_hook = hook; 1525 q->body.data.da_m = m; 1526 q->body.data.da_meta = meta; 1527 hook->refs++; /* don't let it go away while on the queue */ 1528 1529 /* Put it on the queue */ 1530 s = splhigh(); 1531 if (ngqbase) { 1532 ngqlast->next = q; 1533 } else { 1534 ngqbase = q; 1535 } 1536 ngqlast = q; 1537 ngqsize++; 1538 splx(s); 1539 1540 /* Schedule software interrupt to handle it later */ 1541 schednetisr(NETISR_NETGRAPH); 1542 return (0); 1543} 1544 1545/* 1546 * Running at a raised (but we don't know which) processor priority level, 1547 * put the msg onto a queue to be picked up by another PPL (probably splnet) 1548 */ 1549int 1550ng_queue_msg(node_p here, struct ng_mesg * msg, int len, const char *address) 1551{ 1552 register struct ng_queue_entry *q; 1553 int s; 1554 node_p dest = NULL; 1555 char *retaddr = NULL; 1556 int error; 1557 1558 /* Find the target node. */ 1559 error = ng_path2node(here, address, &dest, &retaddr); 1560 if (error) { 1561 FREE(msg, M_NETGRAPH); 1562 return (error); 1563 } 1564 if ((q = ng_getqblk()) == NULL) { 1565 FREE(msg, M_NETGRAPH); 1566 if (retaddr) 1567 FREE(retaddr, M_NETGRAPH); 1568 return (ENOBUFS); 1569 } 1570 1571 /* Fill out the contents */ 1572 q->flags = NGQF_MESG; 1573 q->next = NULL; 1574 q->body.msg.msg_node = dest; 1575 q->body.msg.msg_msg = msg; 1576 q->body.msg.msg_retaddr = retaddr; 1577 dest->refs++; /* don't let it go away while on the queue */ 1578 1579 /* Put it on the queue */ 1580 s = splhigh(); 1581 if (ngqbase) { 1582 ngqlast->next = q; 1583 } else { 1584 ngqbase = q; 1585 } 1586 ngqlast = q; 1587 ngqsize++; 1588 splx(s); 1589 1590 /* Schedule software interrupt to handle it later */ 1591 schednetisr(NETISR_NETGRAPH); 1592 return (0); 1593} 1594 1595/* 1596 * Pick an item off the queue, process it, and dispose of the queue entry. 1597 * Should be running at splnet. 1598 */ 1599static void 1600ngintr(void) 1601{ 1602 hook_p hook; 1603 struct ng_queue_entry *ngq; 1604 struct mbuf *m; 1605 meta_p meta; 1606 void *retaddr; 1607 struct ng_mesg *msg; 1608 node_p node; 1609 int error = 0; 1610 int s; 1611 1612 while (1) { 1613 s = splhigh(); 1614 if ((ngq = ngqbase)) { 1615 ngqbase = ngq->next; 1616 ngqsize--; 1617 } 1618 splx(s); 1619 if (ngq == NULL) 1620 return; 1621 switch (ngq->flags) { 1622 case NGQF_DATA: 1623 hook = ngq->body.data.da_hook; 1624 m = ngq->body.data.da_m; 1625 meta = ngq->body.data.da_meta; 1626 RETURN_QBLK(ngq); 1627 NG_SEND_DATAQ(error, hook, m, meta); 1628 ng_unref_hook(hook); 1629 break; 1630 case NGQF_MESG: 1631 node = ngq->body.msg.msg_node; 1632 msg = ngq->body.msg.msg_msg; 1633 retaddr = ngq->body.msg.msg_retaddr; 1634 RETURN_QBLK(ngq); 1635 if (node->flags & NG_INVALID) { 1636 FREE(msg, M_NETGRAPH); 1637 } else { 1638 CALL_MSG_HANDLER(error, node, msg, 1639 retaddr, NULL); 1640 } 1641 ng_unref(node); 1642 if (retaddr) 1643 FREE(retaddr, M_NETGRAPH); 1644 break; 1645 default: 1646 RETURN_QBLK(ngq); 1647 } 1648 } 1649} 1650 1651 1652