ng_base.c revision 139774
1/* 2 * ng_base.c 3 * 4 * Copyright (c) 1996-1999 Whistle Communications, Inc. 5 * All rights reserved. 6 * 7 * Subject to the following obligations and disclaimer of warranty, use and 8 * redistribution of this software, in source or object code forms, with or 9 * without modifications are expressly permitted by Whistle Communications; 10 * provided, however, that: 11 * 1. Any and all reproductions of the source or object code must include the 12 * copyright notice above and the following disclaimer of warranties; and 13 * 2. No rights are granted, in any manner or form, to use Whistle 14 * Communications, Inc. trademarks, including the mark "WHISTLE 15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16 * such appears in the above copyright notice or in the software. 17 * 18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34 * OF SUCH DAMAGE. 35 * 36 * Authors: Julian Elischer <julian@freebsd.org> 37 * Archie Cobbs <archie@freebsd.org> 38 * 39 * $FreeBSD: head/sys/netgraph/ng_base.c 139774 2005-01-06 17:45:03Z emax $ 40 * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $ 41 */ 42 43/* 44 * This file implements the base netgraph code. 45 */ 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/ctype.h> 50#include <sys/errno.h> 51#include <sys/kdb.h> 52#include <sys/kernel.h> 53#include <sys/limits.h> 54#include <sys/malloc.h> 55#include <sys/mbuf.h> 56#include <sys/queue.h> 57#include <sys/sysctl.h> 58#include <sys/syslog.h> 59 60#include <net/netisr.h> 61 62#include <netgraph/ng_message.h> 63#include <netgraph/netgraph.h> 64#include <netgraph/ng_parse.h> 65 66MODULE_VERSION(netgraph, NG_ABI_VERSION); 67 68/* List of all active nodes */ 69static LIST_HEAD(, ng_node) ng_nodelist; 70static struct mtx ng_nodelist_mtx; 71 72/* Mutex that protects the free queue item list */ 73static struct mtx ngq_mtx; 74 75#ifdef NETGRAPH_DEBUG 76 77static SLIST_HEAD(, ng_node) ng_allnodes; 78static LIST_HEAD(, ng_node) ng_freenodes; /* in debug, we never free() them */ 79static SLIST_HEAD(, ng_hook) ng_allhooks; 80static LIST_HEAD(, ng_hook) ng_freehooks; /* in debug, we never free() them */ 81 82static void ng_dumpitems(void); 83static void ng_dumpnodes(void); 84static void ng_dumphooks(void); 85 86#endif /* NETGRAPH_DEBUG */ 87/* 88 * DEAD versions of the structures. 89 * In order to avoid races, it is sometimes neccesary to point 90 * at SOMETHING even though theoretically, the current entity is 91 * INVALID. Use these to avoid these races. 92 */ 93struct ng_type ng_deadtype = { 94 NG_ABI_VERSION, 95 "dead", 96 NULL, /* modevent */ 97 NULL, /* constructor */ 98 NULL, /* rcvmsg */ 99 NULL, /* shutdown */ 100 NULL, /* newhook */ 101 NULL, /* findhook */ 102 NULL, /* connect */ 103 NULL, /* rcvdata */ 104 NULL, /* disconnect */ 105 NULL, /* cmdlist */ 106}; 107 108struct ng_node ng_deadnode = { 109 "dead", 110 &ng_deadtype, 111 NGF_INVALID, 112 1, /* refs */ 113 0, /* numhooks */ 114 NULL, /* private */ 115 0, /* ID */ 116 LIST_HEAD_INITIALIZER(ng_deadnode.hooks), 117 {}, /* all_nodes list entry */ 118 {}, /* id hashtable list entry */ 119 {}, /* workqueue entry */ 120 { 0, 121 {}, /* should never use! (should hang) */ 122 NULL, 123 &ng_deadnode.nd_input_queue.queue, 124 &ng_deadnode 125 }, 126#ifdef NETGRAPH_DEBUG 127 ND_MAGIC, 128 __FILE__, 129 __LINE__, 130 {NULL} 131#endif /* NETGRAPH_DEBUG */ 132}; 133 134struct ng_hook ng_deadhook = { 135 "dead", 136 NULL, /* private */ 137 HK_INVALID | HK_DEAD, 138 1, /* refs always >= 1 */ 139 &ng_deadhook, /* Peer is self */ 140 &ng_deadnode, /* attached to deadnode */ 141 {}, /* hooks list */ 142 NULL, /* override rcvmsg() */ 143 NULL, /* override rcvdata() */ 144#ifdef NETGRAPH_DEBUG 145 HK_MAGIC, 146 __FILE__, 147 __LINE__, 148 {NULL} 149#endif /* NETGRAPH_DEBUG */ 150}; 151 152/* 153 * END DEAD STRUCTURES 154 */ 155/* List nodes with unallocated work */ 156static TAILQ_HEAD(, ng_node) ng_worklist = TAILQ_HEAD_INITIALIZER(ng_worklist); 157static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */ 158 159/* List of installed types */ 160static LIST_HEAD(, ng_type) ng_typelist; 161static struct mtx ng_typelist_mtx; 162 163/* Hash related definitions */ 164/* XXX Don't need to initialise them because it's a LIST */ 165#define NG_ID_HASH_SIZE 32 /* most systems wont need even this many */ 166static LIST_HEAD(, ng_node) ng_ID_hash[NG_ID_HASH_SIZE]; 167static struct mtx ng_idhash_mtx; 168/* Method to find a node.. used twice so do it here */ 169#define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE)) 170#define NG_IDHASH_FIND(ID, node) \ 171 do { \ 172 mtx_assert(&ng_idhash_mtx, MA_OWNED); \ 173 LIST_FOREACH(node, &ng_ID_hash[NG_IDHASH_FN(ID)], \ 174 nd_idnodes) { \ 175 if (NG_NODE_IS_VALID(node) \ 176 && (NG_NODE_ID(node) == ID)) { \ 177 break; \ 178 } \ 179 } \ 180 } while (0) 181 182 183/* Internal functions */ 184static int ng_add_hook(node_p node, const char *name, hook_p * hookp); 185static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); 186static ng_ID_t ng_decodeidname(const char *name); 187static int ngb_mod_event(module_t mod, int event, void *data); 188static void ng_worklist_remove(node_p node); 189static void ngintr(void); 190static int ng_apply_item(node_p node, item_p item); 191static void ng_flush_input_queue(struct ng_queue * ngq); 192static void ng_setisr(node_p node); 193static node_p ng_ID2noderef(ng_ID_t ID); 194static int ng_con_nodes(node_p node, const char *name, node_p node2, 195 const char *name2); 196static void ng_con_part2(node_p node, hook_p hook, void *arg1, int arg2); 197static void ng_con_part3(node_p node, hook_p hook, void *arg1, int arg2); 198static int ng_mkpeer(node_p node, const char *name, 199 const char *name2, char *type); 200 201/* imported , these used to be externally visible, some may go back */ 202void ng_destroy_hook(hook_p hook); 203node_p ng_name2noderef(node_p node, const char *name); 204int ng_path2noderef(node_p here, const char *path, 205 node_p *dest, hook_p *lasthook); 206int ng_make_node(const char *type, node_p *nodepp); 207int ng_path_parse(char *addr, char **node, char **path, char **hook); 208void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3); 209void ng_unname(node_p node); 210 211 212/* Our own netgraph malloc type */ 213MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages"); 214MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures"); 215MALLOC_DEFINE(M_NETGRAPH_NODE, "netgraph_node", "netgraph node structures"); 216MALLOC_DEFINE(M_NETGRAPH_ITEM, "netgraph_item", "netgraph item structures"); 217MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); 218 219/* Should not be visible outside this file */ 220 221#define _NG_ALLOC_HOOK(hook) \ 222 MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH_HOOK, M_NOWAIT | M_ZERO) 223#define _NG_ALLOC_NODE(node) \ 224 MALLOC(node, node_p, sizeof(*node), M_NETGRAPH_NODE, M_NOWAIT | M_ZERO) 225 226#ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 227/* 228 * In debug mode: 229 * In an attempt to help track reference count screwups 230 * we do not free objects back to the malloc system, but keep them 231 * in a local cache where we can examine them and keep information safely 232 * after they have been freed. 233 * We use this scheme for nodes and hooks, and to some extent for items. 234 */ 235static __inline hook_p 236ng_alloc_hook(void) 237{ 238 hook_p hook; 239 SLIST_ENTRY(ng_hook) temp; 240 mtx_lock(&ng_nodelist_mtx); 241 hook = LIST_FIRST(&ng_freehooks); 242 if (hook) { 243 LIST_REMOVE(hook, hk_hooks); 244 bcopy(&hook->hk_all, &temp, sizeof(temp)); 245 bzero(hook, sizeof(struct ng_hook)); 246 bcopy(&temp, &hook->hk_all, sizeof(temp)); 247 mtx_unlock(&ng_nodelist_mtx); 248 hook->hk_magic = HK_MAGIC; 249 } else { 250 mtx_unlock(&ng_nodelist_mtx); 251 _NG_ALLOC_HOOK(hook); 252 if (hook) { 253 hook->hk_magic = HK_MAGIC; 254 mtx_lock(&ng_nodelist_mtx); 255 SLIST_INSERT_HEAD(&ng_allhooks, hook, hk_all); 256 mtx_unlock(&ng_nodelist_mtx); 257 } 258 } 259 return (hook); 260} 261 262static __inline node_p 263ng_alloc_node(void) 264{ 265 node_p node; 266 SLIST_ENTRY(ng_node) temp; 267 mtx_lock(&ng_nodelist_mtx); 268 node = LIST_FIRST(&ng_freenodes); 269 if (node) { 270 LIST_REMOVE(node, nd_nodes); 271 bcopy(&node->nd_all, &temp, sizeof(temp)); 272 bzero(node, sizeof(struct ng_node)); 273 bcopy(&temp, &node->nd_all, sizeof(temp)); 274 mtx_unlock(&ng_nodelist_mtx); 275 node->nd_magic = ND_MAGIC; 276 } else { 277 mtx_unlock(&ng_nodelist_mtx); 278 _NG_ALLOC_NODE(node); 279 if (node) { 280 node->nd_magic = ND_MAGIC; 281 mtx_lock(&ng_nodelist_mtx); 282 SLIST_INSERT_HEAD(&ng_allnodes, node, nd_all); 283 mtx_unlock(&ng_nodelist_mtx); 284 } 285 } 286 return (node); 287} 288 289#define NG_ALLOC_HOOK(hook) do { (hook) = ng_alloc_hook(); } while (0) 290#define NG_ALLOC_NODE(node) do { (node) = ng_alloc_node(); } while (0) 291 292 293#define NG_FREE_HOOK(hook) \ 294 do { \ 295 mtx_lock(&ng_nodelist_mtx); \ 296 LIST_INSERT_HEAD(&ng_freehooks, hook, hk_hooks); \ 297 hook->hk_magic = 0; \ 298 mtx_unlock(&ng_nodelist_mtx); \ 299 } while (0) 300 301#define NG_FREE_NODE(node) \ 302 do { \ 303 mtx_lock(&ng_nodelist_mtx); \ 304 LIST_INSERT_HEAD(&ng_freenodes, node, nd_nodes); \ 305 node->nd_magic = 0; \ 306 mtx_unlock(&ng_nodelist_mtx); \ 307 } while (0) 308 309#else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 310 311#define NG_ALLOC_HOOK(hook) _NG_ALLOC_HOOK(hook) 312#define NG_ALLOC_NODE(node) _NG_ALLOC_NODE(node) 313 314#define NG_FREE_HOOK(hook) do { FREE((hook), M_NETGRAPH_HOOK); } while (0) 315#define NG_FREE_NODE(node) do { FREE((node), M_NETGRAPH_NODE); } while (0) 316 317#endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 318 319/* Warning: Generally use NG_FREE_ITEM() instead */ 320#define NG_FREE_ITEM_REAL(item) do { FREE((item), M_NETGRAPH_ITEM); } while (0) 321 322 323/* Set this to kdb_enter("X") to catch all errors as they occur */ 324#ifndef TRAP_ERROR 325#define TRAP_ERROR() 326#endif 327 328static ng_ID_t nextID = 1; 329 330#ifdef INVARIANTS 331#define CHECK_DATA_MBUF(m) do { \ 332 struct mbuf *n; \ 333 int total; \ 334 \ 335 M_ASSERTPKTHDR(m); \ 336 for (total = 0, n = (m); n != NULL; n = n->m_next) \ 337 total += n->m_len; \ 338 if ((m)->m_pkthdr.len != total) { \ 339 panic("%s: %d != %d", \ 340 __func__, (m)->m_pkthdr.len, total); \ 341 } \ 342 } while (0) 343#else 344#define CHECK_DATA_MBUF(m) 345#endif 346 347 348/************************************************************************ 349 Parse type definitions for generic messages 350************************************************************************/ 351 352/* Handy structure parse type defining macro */ 353#define DEFINE_PARSE_STRUCT_TYPE(lo, up, args) \ 354static const struct ng_parse_struct_field \ 355 ng_ ## lo ## _type_fields[] = NG_GENERIC_ ## up ## _INFO args; \ 356static const struct ng_parse_type ng_generic_ ## lo ## _type = { \ 357 &ng_parse_struct_type, \ 358 &ng_ ## lo ## _type_fields \ 359} 360 361DEFINE_PARSE_STRUCT_TYPE(mkpeer, MKPEER, ()); 362DEFINE_PARSE_STRUCT_TYPE(connect, CONNECT, ()); 363DEFINE_PARSE_STRUCT_TYPE(name, NAME, ()); 364DEFINE_PARSE_STRUCT_TYPE(rmhook, RMHOOK, ()); 365DEFINE_PARSE_STRUCT_TYPE(nodeinfo, NODEINFO, ()); 366DEFINE_PARSE_STRUCT_TYPE(typeinfo, TYPEINFO, ()); 367DEFINE_PARSE_STRUCT_TYPE(linkinfo, LINKINFO, (&ng_generic_nodeinfo_type)); 368 369/* Get length of an array when the length is stored as a 32 bit 370 value immediately preceding the array -- as with struct namelist 371 and struct typelist. */ 372static int 373ng_generic_list_getLength(const struct ng_parse_type *type, 374 const u_char *start, const u_char *buf) 375{ 376 return *((const u_int32_t *)(buf - 4)); 377} 378 379/* Get length of the array of struct linkinfo inside a struct hooklist */ 380static int 381ng_generic_linkinfo_getLength(const struct ng_parse_type *type, 382 const u_char *start, const u_char *buf) 383{ 384 const struct hooklist *hl = (const struct hooklist *)start; 385 386 return hl->nodeinfo.hooks; 387} 388 389/* Array type for a variable length array of struct namelist */ 390static const struct ng_parse_array_info ng_nodeinfoarray_type_info = { 391 &ng_generic_nodeinfo_type, 392 &ng_generic_list_getLength 393}; 394static const struct ng_parse_type ng_generic_nodeinfoarray_type = { 395 &ng_parse_array_type, 396 &ng_nodeinfoarray_type_info 397}; 398 399/* Array type for a variable length array of struct typelist */ 400static const struct ng_parse_array_info ng_typeinfoarray_type_info = { 401 &ng_generic_typeinfo_type, 402 &ng_generic_list_getLength 403}; 404static const struct ng_parse_type ng_generic_typeinfoarray_type = { 405 &ng_parse_array_type, 406 &ng_typeinfoarray_type_info 407}; 408 409/* Array type for array of struct linkinfo in struct hooklist */ 410static const struct ng_parse_array_info ng_generic_linkinfo_array_type_info = { 411 &ng_generic_linkinfo_type, 412 &ng_generic_linkinfo_getLength 413}; 414static const struct ng_parse_type ng_generic_linkinfo_array_type = { 415 &ng_parse_array_type, 416 &ng_generic_linkinfo_array_type_info 417}; 418 419DEFINE_PARSE_STRUCT_TYPE(typelist, TYPELIST, (&ng_generic_nodeinfoarray_type)); 420DEFINE_PARSE_STRUCT_TYPE(hooklist, HOOKLIST, 421 (&ng_generic_nodeinfo_type, &ng_generic_linkinfo_array_type)); 422DEFINE_PARSE_STRUCT_TYPE(listnodes, LISTNODES, 423 (&ng_generic_nodeinfoarray_type)); 424 425/* List of commands and how to convert arguments to/from ASCII */ 426static const struct ng_cmdlist ng_generic_cmds[] = { 427 { 428 NGM_GENERIC_COOKIE, 429 NGM_SHUTDOWN, 430 "shutdown", 431 NULL, 432 NULL 433 }, 434 { 435 NGM_GENERIC_COOKIE, 436 NGM_MKPEER, 437 "mkpeer", 438 &ng_generic_mkpeer_type, 439 NULL 440 }, 441 { 442 NGM_GENERIC_COOKIE, 443 NGM_CONNECT, 444 "connect", 445 &ng_generic_connect_type, 446 NULL 447 }, 448 { 449 NGM_GENERIC_COOKIE, 450 NGM_NAME, 451 "name", 452 &ng_generic_name_type, 453 NULL 454 }, 455 { 456 NGM_GENERIC_COOKIE, 457 NGM_RMHOOK, 458 "rmhook", 459 &ng_generic_rmhook_type, 460 NULL 461 }, 462 { 463 NGM_GENERIC_COOKIE, 464 NGM_NODEINFO, 465 "nodeinfo", 466 NULL, 467 &ng_generic_nodeinfo_type 468 }, 469 { 470 NGM_GENERIC_COOKIE, 471 NGM_LISTHOOKS, 472 "listhooks", 473 NULL, 474 &ng_generic_hooklist_type 475 }, 476 { 477 NGM_GENERIC_COOKIE, 478 NGM_LISTNAMES, 479 "listnames", 480 NULL, 481 &ng_generic_listnodes_type /* same as NGM_LISTNODES */ 482 }, 483 { 484 NGM_GENERIC_COOKIE, 485 NGM_LISTNODES, 486 "listnodes", 487 NULL, 488 &ng_generic_listnodes_type 489 }, 490 { 491 NGM_GENERIC_COOKIE, 492 NGM_LISTTYPES, 493 "listtypes", 494 NULL, 495 &ng_generic_typeinfo_type 496 }, 497 { 498 NGM_GENERIC_COOKIE, 499 NGM_TEXT_CONFIG, 500 "textconfig", 501 NULL, 502 &ng_parse_string_type 503 }, 504 { 505 NGM_GENERIC_COOKIE, 506 NGM_TEXT_STATUS, 507 "textstatus", 508 NULL, 509 &ng_parse_string_type 510 }, 511 { 512 NGM_GENERIC_COOKIE, 513 NGM_ASCII2BINARY, 514 "ascii2binary", 515 &ng_parse_ng_mesg_type, 516 &ng_parse_ng_mesg_type 517 }, 518 { 519 NGM_GENERIC_COOKIE, 520 NGM_BINARY2ASCII, 521 "binary2ascii", 522 &ng_parse_ng_mesg_type, 523 &ng_parse_ng_mesg_type 524 }, 525 { 0 } 526}; 527 528/************************************************************************ 529 Node routines 530************************************************************************/ 531 532/* 533 * Instantiate a node of the requested type 534 */ 535int 536ng_make_node(const char *typename, node_p *nodepp) 537{ 538 struct ng_type *type; 539 int error; 540 541 /* Check that the type makes sense */ 542 if (typename == NULL) { 543 TRAP_ERROR(); 544 return (EINVAL); 545 } 546 547 /* Locate the node type. If we fail we return. Do not try to load 548 * module. 549 */ 550 if ((type = ng_findtype(typename)) == NULL) 551 return (ENXIO); 552 553 /* 554 * If we have a constructor, then make the node and 555 * call the constructor to do type specific initialisation. 556 */ 557 if (type->constructor != NULL) { 558 if ((error = ng_make_node_common(type, nodepp)) == 0) { 559 if ((error = ((*type->constructor)(*nodepp)) != 0)) { 560 NG_NODE_UNREF(*nodepp); 561 } 562 } 563 } else { 564 /* 565 * Node has no constructor. We cannot ask for one 566 * to be made. It must be brought into existance by 567 * some external agency. The external agency should 568 * call ng_make_node_common() directly to get the 569 * netgraph part initialised. 570 */ 571 TRAP_ERROR(); 572 error = EINVAL; 573 } 574 return (error); 575} 576 577/* 578 * Generic node creation. Called by node initialisation for externally 579 * instantiated nodes (e.g. hardware, sockets, etc ). 580 * The returned node has a reference count of 1. 581 */ 582int 583ng_make_node_common(struct ng_type *type, node_p *nodepp) 584{ 585 node_p node; 586 587 /* Require the node type to have been already installed */ 588 if (ng_findtype(type->name) == NULL) { 589 TRAP_ERROR(); 590 return (EINVAL); 591 } 592 593 /* Make a node and try attach it to the type */ 594 NG_ALLOC_NODE(node); 595 if (node == NULL) { 596 TRAP_ERROR(); 597 return (ENOMEM); 598 } 599 node->nd_type = type; 600 NG_NODE_REF(node); /* note reference */ 601 type->refs++; 602 603 mtx_init(&node->nd_input_queue.q_mtx, "ng_node", NULL, MTX_SPIN); 604 node->nd_input_queue.queue = NULL; 605 node->nd_input_queue.last = &node->nd_input_queue.queue; 606 node->nd_input_queue.q_flags = 0; 607 node->nd_input_queue.q_node = node; 608 609 /* Initialize hook list for new node */ 610 LIST_INIT(&node->nd_hooks); 611 612 /* Link us into the node linked list */ 613 mtx_lock(&ng_nodelist_mtx); 614 LIST_INSERT_HEAD(&ng_nodelist, node, nd_nodes); 615 mtx_unlock(&ng_nodelist_mtx); 616 617 618 /* get an ID and put us in the hash chain */ 619 mtx_lock(&ng_idhash_mtx); 620 for (;;) { /* wrap protection, even if silly */ 621 node_p node2 = NULL; 622 node->nd_ID = nextID++; /* 137/second for 1 year before wrap */ 623 624 /* Is there a problem with the new number? */ 625 NG_IDHASH_FIND(node->nd_ID, node2); /* already taken? */ 626 if ((node->nd_ID != 0) && (node2 == NULL)) { 627 break; 628 } 629 } 630 LIST_INSERT_HEAD(&ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], 631 node, nd_idnodes); 632 mtx_unlock(&ng_idhash_mtx); 633 634 /* Done */ 635 *nodepp = node; 636 return (0); 637} 638 639/* 640 * Forceably start the shutdown process on a node. Either call 641 * it's shutdown method, or do the default shutdown if there is 642 * no type-specific method. 643 * 644 * We can only be called form a shutdown message, so we know we have 645 * a writer lock, and therefore exclusive access. It also means 646 * that we should not be on the work queue, but we check anyhow. 647 * 648 * Persistent node types must have a type-specific method which 649 * Allocates a new node in which case, this one is irretrievably going away, 650 * or cleans up anything it needs, and just makes the node valid again, 651 * in which case we allow the node to survive. 652 * 653 * XXX We need to think of how to tell a persistant node that we 654 * REALLY need to go away because the hardware has gone or we 655 * are rebooting.... etc. 656 */ 657void 658ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3) 659{ 660 hook_p hook; 661 662 /* Check if it's already shutting down */ 663 if ((node->nd_flags & NGF_CLOSING) != 0) 664 return; 665 666 if (node == &ng_deadnode) { 667 printf ("shutdown called on deadnode\n"); 668 return; 669 } 670 671 /* Add an extra reference so it doesn't go away during this */ 672 NG_NODE_REF(node); 673 674 /* 675 * Mark it invalid so any newcomers know not to try use it 676 * Also add our own mark so we can't recurse 677 * note that NGF_INVALID does not do this as it's also set during 678 * creation 679 */ 680 node->nd_flags |= NGF_INVALID|NGF_CLOSING; 681 682 /* If node has its pre-shutdown method, then call it first*/ 683 if (node->nd_type && node->nd_type->close) 684 (*node->nd_type->close)(node); 685 686 /* Notify all remaining connected nodes to disconnect */ 687 while ((hook = LIST_FIRST(&node->nd_hooks)) != NULL) 688 ng_destroy_hook(hook); 689 690 /* 691 * Drain the input queue forceably. 692 * it has no hooks so what's it going to do, bleed on someone? 693 * Theoretically we came here from a queue entry that was added 694 * Just before the queue was closed, so it should be empty anyway. 695 * Also removes us from worklist if needed. 696 */ 697 ng_flush_input_queue(&node->nd_input_queue); 698 699 /* Ask the type if it has anything to do in this case */ 700 if (node->nd_type && node->nd_type->shutdown) { 701 (*node->nd_type->shutdown)(node); 702 if (NG_NODE_IS_VALID(node)) { 703 /* 704 * Well, blow me down if the node code hasn't declared 705 * that it doesn't want to die. 706 * Presumably it is a persistant node. 707 * If we REALLY want it to go away, 708 * e.g. hardware going away, 709 * Our caller should set NGF_REALLY_DIE in nd_flags. 710 */ 711 node->nd_flags &= ~(NGF_INVALID|NGF_CLOSING); 712 NG_NODE_UNREF(node); /* Assume they still have theirs */ 713 return; 714 } 715 } else { /* do the default thing */ 716 NG_NODE_UNREF(node); 717 } 718 719 ng_unname(node); /* basically a NOP these days */ 720 721 /* 722 * Remove extra reference, possibly the last 723 * Possible other holders of references may include 724 * timeout callouts, but theoretically the node's supposed to 725 * have cancelled them. Possibly hardware dependencies may 726 * force a driver to 'linger' with a reference. 727 */ 728 NG_NODE_UNREF(node); 729} 730 731#ifdef NETGRAPH_DEBUG 732void 733ng_ref_node(node_p node) 734{ 735 _NG_NODE_REF(node); 736} 737#endif 738 739/* 740 * Remove a reference to the node, possibly the last. 741 * deadnode always acts as it it were the last. 742 */ 743int 744ng_unref_node(node_p node) 745{ 746 int v; 747 748 if (node == &ng_deadnode) { 749 return (0); 750 } 751 752 do { 753 v = node->nd_refs - 1; 754 } while (! atomic_cmpset_int(&node->nd_refs, v + 1, v)); 755 756 if (v == 0) { /* we were the last */ 757 758 mtx_lock(&ng_nodelist_mtx); 759 node->nd_type->refs--; /* XXX maybe should get types lock? */ 760 LIST_REMOVE(node, nd_nodes); 761 mtx_unlock(&ng_nodelist_mtx); 762 763 mtx_lock(&ng_idhash_mtx); 764 LIST_REMOVE(node, nd_idnodes); 765 mtx_unlock(&ng_idhash_mtx); 766 767 mtx_destroy(&node->nd_input_queue.q_mtx); 768 NG_FREE_NODE(node); 769 } 770 return (v); 771} 772 773/************************************************************************ 774 Node ID handling 775************************************************************************/ 776static node_p 777ng_ID2noderef(ng_ID_t ID) 778{ 779 node_p node; 780 mtx_lock(&ng_idhash_mtx); 781 NG_IDHASH_FIND(ID, node); 782 if(node) 783 NG_NODE_REF(node); 784 mtx_unlock(&ng_idhash_mtx); 785 return(node); 786} 787 788ng_ID_t 789ng_node2ID(node_p node) 790{ 791 return (node ? NG_NODE_ID(node) : 0); 792} 793 794/************************************************************************ 795 Node name handling 796************************************************************************/ 797 798/* 799 * Assign a node a name. Once assigned, the name cannot be changed. 800 */ 801int 802ng_name_node(node_p node, const char *name) 803{ 804 int i; 805 node_p node2; 806 807 /* Check the name is valid */ 808 for (i = 0; i < NG_NODESIZ; i++) { 809 if (name[i] == '\0' || name[i] == '.' || name[i] == ':') 810 break; 811 } 812 if (i == 0 || name[i] != '\0') { 813 TRAP_ERROR(); 814 return (EINVAL); 815 } 816 if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */ 817 TRAP_ERROR(); 818 return (EINVAL); 819 } 820 821 /* Check the name isn't already being used */ 822 if ((node2 = ng_name2noderef(node, name)) != NULL) { 823 NG_NODE_UNREF(node2); 824 TRAP_ERROR(); 825 return (EADDRINUSE); 826 } 827 828 /* copy it */ 829 strlcpy(NG_NODE_NAME(node), name, NG_NODESIZ); 830 831 return (0); 832} 833 834/* 835 * Find a node by absolute name. The name should NOT end with ':' 836 * The name "." means "this node" and "[xxx]" means "the node 837 * with ID (ie, at address) xxx". 838 * 839 * Returns the node if found, else NULL. 840 * Eventually should add something faster than a sequential search. 841 * Note it aquires a reference on the node so you can be sure it's still there. 842 */ 843node_p 844ng_name2noderef(node_p here, const char *name) 845{ 846 node_p node; 847 ng_ID_t temp; 848 849 /* "." means "this node" */ 850 if (strcmp(name, ".") == 0) { 851 NG_NODE_REF(here); 852 return(here); 853 } 854 855 /* Check for name-by-ID */ 856 if ((temp = ng_decodeidname(name)) != 0) { 857 return (ng_ID2noderef(temp)); 858 } 859 860 /* Find node by name */ 861 mtx_lock(&ng_nodelist_mtx); 862 LIST_FOREACH(node, &ng_nodelist, nd_nodes) { 863 if (NG_NODE_IS_VALID(node) 864 && NG_NODE_HAS_NAME(node) 865 && (strcmp(NG_NODE_NAME(node), name) == 0)) { 866 break; 867 } 868 } 869 if (node) 870 NG_NODE_REF(node); 871 mtx_unlock(&ng_nodelist_mtx); 872 return (node); 873} 874 875/* 876 * Decode an ID name, eg. "[f03034de]". Returns 0 if the 877 * string is not valid, otherwise returns the value. 878 */ 879static ng_ID_t 880ng_decodeidname(const char *name) 881{ 882 const int len = strlen(name); 883 char *eptr; 884 u_long val; 885 886 /* Check for proper length, brackets, no leading junk */ 887 if ((len < 3) 888 || (name[0] != '[') 889 || (name[len - 1] != ']') 890 || (!isxdigit(name[1]))) { 891 return ((ng_ID_t)0); 892 } 893 894 /* Decode number */ 895 val = strtoul(name + 1, &eptr, 16); 896 if ((eptr - name != len - 1) 897 || (val == ULONG_MAX) 898 || (val == 0)) { 899 return ((ng_ID_t)0); 900 } 901 return (ng_ID_t)val; 902} 903 904/* 905 * Remove a name from a node. This should only be called 906 * when shutting down and removing the node. 907 * IF we allow name changing this may be more resurected. 908 */ 909void 910ng_unname(node_p node) 911{ 912} 913 914/************************************************************************ 915 Hook routines 916 Names are not optional. Hooks are always connected, except for a 917 brief moment within these routines. On invalidation or during creation 918 they are connected to the 'dead' hook. 919************************************************************************/ 920 921/* 922 * Remove a hook reference 923 */ 924void 925ng_unref_hook(hook_p hook) 926{ 927 int v; 928 929 if (hook == &ng_deadhook) { 930 return; 931 } 932 do { 933 v = hook->hk_refs; 934 } while (! atomic_cmpset_int(&hook->hk_refs, v, v - 1)); 935 936 if (v == 1) { /* we were the last */ 937 if (_NG_HOOK_NODE(hook)) { /* it'll probably be ng_deadnode */ 938 _NG_NODE_UNREF((_NG_HOOK_NODE(hook))); 939 hook->hk_node = NULL; 940 } 941 NG_FREE_HOOK(hook); 942 } 943} 944 945/* 946 * Add an unconnected hook to a node. Only used internally. 947 * Assumes node is locked. (XXX not yet true ) 948 */ 949static int 950ng_add_hook(node_p node, const char *name, hook_p *hookp) 951{ 952 hook_p hook; 953 int error = 0; 954 955 /* Check that the given name is good */ 956 if (name == NULL) { 957 TRAP_ERROR(); 958 return (EINVAL); 959 } 960 if (ng_findhook(node, name) != NULL) { 961 TRAP_ERROR(); 962 return (EEXIST); 963 } 964 965 /* Allocate the hook and link it up */ 966 NG_ALLOC_HOOK(hook); 967 if (hook == NULL) { 968 TRAP_ERROR(); 969 return (ENOMEM); 970 } 971 hook->hk_refs = 1; /* add a reference for us to return */ 972 hook->hk_flags = HK_INVALID; 973 hook->hk_peer = &ng_deadhook; /* start off this way */ 974 hook->hk_node = node; 975 NG_NODE_REF(node); /* each hook counts as a reference */ 976 977 /* Set hook name */ 978 strlcpy(NG_HOOK_NAME(hook), name, NG_HOOKSIZ); 979 980 /* 981 * Check if the node type code has something to say about it 982 * If it fails, the unref of the hook will also unref the node. 983 */ 984 if (node->nd_type->newhook != NULL) { 985 if ((error = (*node->nd_type->newhook)(node, hook, name))) { 986 NG_HOOK_UNREF(hook); /* this frees the hook */ 987 return (error); 988 } 989 } 990 /* 991 * The 'type' agrees so far, so go ahead and link it in. 992 * We'll ask again later when we actually connect the hooks. 993 */ 994 LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 995 node->nd_numhooks++; 996 NG_HOOK_REF(hook); /* one for the node */ 997 998 if (hookp) 999 *hookp = hook; 1000 return (0); 1001} 1002 1003/* 1004 * Find a hook 1005 * 1006 * Node types may supply their own optimized routines for finding 1007 * hooks. If none is supplied, we just do a linear search. 1008 * XXX Possibly we should add a reference to the hook? 1009 */ 1010hook_p 1011ng_findhook(node_p node, const char *name) 1012{ 1013 hook_p hook; 1014 1015 if (node->nd_type->findhook != NULL) 1016 return (*node->nd_type->findhook)(node, name); 1017 LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { 1018 if (NG_HOOK_IS_VALID(hook) 1019 && (strcmp(NG_HOOK_NAME(hook), name) == 0)) 1020 return (hook); 1021 } 1022 return (NULL); 1023} 1024 1025/* 1026 * Destroy a hook 1027 * 1028 * As hooks are always attached, this really destroys two hooks. 1029 * The one given, and the one attached to it. Disconnect the hooks 1030 * from each other first. We reconnect the peer hook to the 'dead' 1031 * hook so that it can still exist after we depart. We then 1032 * send the peer its own destroy message. This ensures that we only 1033 * interact with the peer's structures when it is locked processing that 1034 * message. We hold a reference to the peer hook so we are guaranteed that 1035 * the peer hook and node are still going to exist until 1036 * we are finished there as the hook holds a ref on the node. 1037 * We run this same code again on the peer hook, but that time it is already 1038 * attached to the 'dead' hook. 1039 * 1040 * This routine is called at all stages of hook creation 1041 * on error detection and must be able to handle any such stage. 1042 */ 1043void 1044ng_destroy_hook(hook_p hook) 1045{ 1046 hook_p peer = NG_HOOK_PEER(hook); 1047 node_p node = NG_HOOK_NODE(hook); 1048 1049 if (hook == &ng_deadhook) { /* better safe than sorry */ 1050 printf("ng_destroy_hook called on deadhook\n"); 1051 return; 1052 } 1053 hook->hk_flags |= HK_INVALID; /* as soon as possible */ 1054 if (peer && (peer != &ng_deadhook)) { 1055 /* 1056 * Set the peer to point to ng_deadhook 1057 * from this moment on we are effectively independent it. 1058 * send it an rmhook message of it's own. 1059 */ 1060 peer->hk_peer = &ng_deadhook; /* They no longer know us */ 1061 hook->hk_peer = &ng_deadhook; /* Nor us, them */ 1062 if (NG_HOOK_NODE(peer) == &ng_deadnode) { 1063 /* 1064 * If it's already divorced from a node, 1065 * just free it. 1066 */ 1067 /* nothing */ 1068 } else { 1069 ng_rmhook_self(peer); /* Send it a surprise */ 1070 } 1071 NG_HOOK_UNREF(peer); /* account for peer link */ 1072 NG_HOOK_UNREF(hook); /* account for peer link */ 1073 } 1074 1075 /* 1076 * Remove the hook from the node's list to avoid possible recursion 1077 * in case the disconnection results in node shutdown. 1078 */ 1079 if (node == &ng_deadnode) { /* happens if called from ng_con_nodes() */ 1080 return; 1081 } 1082 LIST_REMOVE(hook, hk_hooks); 1083 node->nd_numhooks--; 1084 if (node->nd_type->disconnect) { 1085 /* 1086 * The type handler may elect to destroy the node so don't 1087 * trust its existance after this point. (except 1088 * that we still hold a reference on it. (which we 1089 * inherrited from the hook we are destroying) 1090 */ 1091 (*node->nd_type->disconnect) (hook); 1092 } 1093 1094 /* 1095 * Note that because we will point to ng_deadnode, the original node 1096 * is not decremented automatically so we do that manually. 1097 */ 1098 _NG_HOOK_NODE(hook) = &ng_deadnode; 1099 NG_NODE_UNREF(node); /* We no longer point to it so adjust count */ 1100 NG_HOOK_UNREF(hook); /* Account for linkage (in list) to node */ 1101} 1102 1103/* 1104 * Take two hooks on a node and merge the connection so that the given node 1105 * is effectively bypassed. 1106 */ 1107int 1108ng_bypass(hook_p hook1, hook_p hook2) 1109{ 1110 if (hook1->hk_node != hook2->hk_node) { 1111 TRAP_ERROR(); 1112 return (EINVAL); 1113 } 1114 hook1->hk_peer->hk_peer = hook2->hk_peer; 1115 hook2->hk_peer->hk_peer = hook1->hk_peer; 1116 1117 hook1->hk_peer = &ng_deadhook; 1118 hook2->hk_peer = &ng_deadhook; 1119 1120 /* XXX If we ever cache methods on hooks update them as well */ 1121 ng_destroy_hook(hook1); 1122 ng_destroy_hook(hook2); 1123 return (0); 1124} 1125 1126/* 1127 * Install a new netgraph type 1128 */ 1129int 1130ng_newtype(struct ng_type *tp) 1131{ 1132 const size_t namelen = strlen(tp->name); 1133 1134 /* Check version and type name fields */ 1135 if ((tp->version != NG_ABI_VERSION) 1136 || (namelen == 0) 1137 || (namelen >= NG_TYPESIZ)) { 1138 TRAP_ERROR(); 1139 if (tp->version != NG_ABI_VERSION) { 1140 printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n"); 1141 } 1142 return (EINVAL); 1143 } 1144 1145 /* Check for name collision */ 1146 if (ng_findtype(tp->name) != NULL) { 1147 TRAP_ERROR(); 1148 return (EEXIST); 1149 } 1150 1151 1152 /* Link in new type */ 1153 mtx_lock(&ng_typelist_mtx); 1154 LIST_INSERT_HEAD(&ng_typelist, tp, types); 1155 tp->refs = 1; /* first ref is linked list */ 1156 mtx_unlock(&ng_typelist_mtx); 1157 return (0); 1158} 1159 1160/* 1161 * unlink a netgraph type 1162 * If no examples exist 1163 */ 1164int 1165ng_rmtype(struct ng_type *tp) 1166{ 1167 /* Check for name collision */ 1168 if (tp->refs != 1) { 1169 TRAP_ERROR(); 1170 return (EBUSY); 1171 } 1172 1173 /* Unlink type */ 1174 mtx_lock(&ng_typelist_mtx); 1175 LIST_REMOVE(tp, types); 1176 mtx_unlock(&ng_typelist_mtx); 1177 return (0); 1178} 1179 1180/* 1181 * Look for a type of the name given 1182 */ 1183struct ng_type * 1184ng_findtype(const char *typename) 1185{ 1186 struct ng_type *type; 1187 1188 mtx_lock(&ng_typelist_mtx); 1189 LIST_FOREACH(type, &ng_typelist, types) { 1190 if (strcmp(type->name, typename) == 0) 1191 break; 1192 } 1193 mtx_unlock(&ng_typelist_mtx); 1194 return (type); 1195} 1196 1197/************************************************************************ 1198 Composite routines 1199************************************************************************/ 1200/* 1201 * Connect two nodes using the specified hooks, using queued functions. 1202 */ 1203static void 1204ng_con_part3(node_p node, hook_p hook, void *arg1, int arg2) 1205{ 1206 1207 /* 1208 * When we run, we know that the node 'node' is locked for us. 1209 * Our caller has a reference on the hook. 1210 * Our caller has a reference on the node. 1211 * (In this case our caller is ng_apply_item() ). 1212 * The peer hook has a reference on the hook. 1213 * We are all set up except for the final call to the node, and 1214 * the clearing of the INVALID flag. 1215 */ 1216 if (NG_HOOK_NODE(hook) == &ng_deadnode) { 1217 /* 1218 * The node must have been freed again since we last visited 1219 * here. ng_destry_hook() has this effect but nothing else does. 1220 * We should just release our references and 1221 * free anything we can think of. 1222 * Since we know it's been destroyed, and it's our caller 1223 * that holds the references, just return. 1224 */ 1225 return ; 1226 } 1227 if (hook->hk_node->nd_type->connect) { 1228 if ((*hook->hk_node->nd_type->connect) (hook)) { 1229 ng_destroy_hook(hook); /* also zaps peer */ 1230 printf("failed in ng_con_part3()\n"); 1231 return ; 1232 } 1233 } 1234 /* 1235 * XXX this is wrong for SMP. Possibly we need 1236 * to separate out 'create' and 'invalid' flags. 1237 * should only set flags on hooks we have locked under our node. 1238 */ 1239 hook->hk_flags &= ~HK_INVALID; 1240 return ; 1241} 1242 1243static void 1244ng_con_part2(node_p node, hook_p hook, void *arg1, int arg2) 1245{ 1246 1247 /* 1248 * When we run, we know that the node 'node' is locked for us. 1249 * Our caller has a reference on the hook. 1250 * Our caller has a reference on the node. 1251 * (In this case our caller is ng_apply_item() ). 1252 * The peer hook has a reference on the hook. 1253 * our node pointer points to the 'dead' node. 1254 * First check the hook name is unique. 1255 * Should not happen because we checked before queueing this. 1256 */ 1257 if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) { 1258 TRAP_ERROR(); 1259 ng_destroy_hook(hook); /* should destroy peer too */ 1260 printf("failed in ng_con_part2()\n"); 1261 return ; 1262 } 1263 /* 1264 * Check if the node type code has something to say about it 1265 * If it fails, the unref of the hook will also unref the attached node, 1266 * however since that node is 'ng_deadnode' this will do nothing. 1267 * The peer hook will also be destroyed. 1268 */ 1269 if (node->nd_type->newhook != NULL) { 1270 if ((*node->nd_type->newhook)(node, hook, hook->hk_name)) { 1271 ng_destroy_hook(hook); /* should destroy peer too */ 1272 printf("failed in ng_con_part2()\n"); 1273 return ; 1274 } 1275 } 1276 1277 /* 1278 * The 'type' agrees so far, so go ahead and link it in. 1279 * We'll ask again later when we actually connect the hooks. 1280 */ 1281 hook->hk_node = node; /* just overwrite ng_deadnode */ 1282 NG_NODE_REF(node); /* each hook counts as a reference */ 1283 LIST_INSERT_HEAD(&node->nd_hooks, hook, hk_hooks); 1284 node->nd_numhooks++; 1285 NG_HOOK_REF(hook); /* one for the node */ 1286 1287 /* 1288 * We now have a symetrical situation, where both hooks have been 1289 * linked to their nodes, the newhook methods have been called 1290 * And the references are all correct. The hooks are still marked 1291 * as invalid, as we have not called the 'connect' methods 1292 * yet. 1293 * We can call the local one immediatly as we have the 1294 * node locked, but we need to queue the remote one. 1295 */ 1296 if (hook->hk_node->nd_type->connect) { 1297 if ((*hook->hk_node->nd_type->connect) (hook)) { 1298 ng_destroy_hook(hook); /* also zaps peer */ 1299 printf("failed in ng_con_part2(A)\n"); 1300 return ; 1301 } 1302 } 1303 if (ng_send_fn(hook->hk_peer->hk_node, hook->hk_peer, 1304 &ng_con_part3, arg1, arg2)) { 1305 printf("failed in ng_con_part2(B)"); 1306 ng_destroy_hook(hook); /* also zaps peer */ 1307 return ; 1308 } 1309 hook->hk_flags &= ~HK_INVALID; /* need both to be able to work */ 1310 return ; 1311} 1312 1313/* 1314 * Connect this node with another node. We assume that this node is 1315 * currently locked, as we are only called from an NGM_CONNECT message. 1316 */ 1317static int 1318ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2) 1319{ 1320 int error; 1321 hook_p hook; 1322 hook_p hook2; 1323 1324 if (ng_findhook(node2, name2) != NULL) { 1325 return(EEXIST); 1326 } 1327 if ((error = ng_add_hook(node, name, &hook))) /* gives us a ref */ 1328 return (error); 1329 /* Allocate the other hook and link it up */ 1330 NG_ALLOC_HOOK(hook2); 1331 if (hook == NULL) { 1332 TRAP_ERROR(); 1333 ng_destroy_hook(hook); /* XXX check ref counts so far */ 1334 NG_HOOK_UNREF(hook); /* including our ref */ 1335 return (ENOMEM); 1336 } 1337 hook2->hk_refs = 1; /* start with a reference for us. */ 1338 hook2->hk_flags = HK_INVALID; 1339 hook2->hk_peer = hook; /* Link the two together */ 1340 hook->hk_peer = hook2; 1341 NG_HOOK_REF(hook); /* Add a ref for the peer to each*/ 1342 NG_HOOK_REF(hook2); 1343 hook2->hk_node = &ng_deadnode; 1344 strlcpy(NG_HOOK_NAME(hook2), name2, NG_HOOKSIZ); 1345 1346 /* 1347 * Queue the function above. 1348 * Procesing continues in that function in the lock context of 1349 * the other node. 1350 */ 1351 ng_send_fn(node2, hook2, &ng_con_part2, NULL, 0); 1352 1353 NG_HOOK_UNREF(hook); /* Let each hook go if it wants to */ 1354 NG_HOOK_UNREF(hook2); 1355 return (0); 1356} 1357 1358/* 1359 * Make a peer and connect. 1360 * We assume that the local node is locked. 1361 * The new node probably doesn't need a lock until 1362 * it has a hook, because it cannot really have any work until then, 1363 * but we should think about it a bit more. 1364 * 1365 * The problem may come if the other node also fires up 1366 * some hardware or a timer or some other source of activation, 1367 * also it may already get a command msg via it's ID. 1368 * 1369 * We could use the same method as ng_con_nodes() but we'd have 1370 * to add ability to remove the node when failing. (Not hard, just 1371 * make arg1 point to the node to remove). 1372 * Unless of course we just ignore failure to connect and leave 1373 * an unconnected node? 1374 */ 1375static int 1376ng_mkpeer(node_p node, const char *name, const char *name2, char *type) 1377{ 1378 node_p node2; 1379 hook_p hook1; 1380 hook_p hook2; 1381 int error; 1382 1383 if ((error = ng_make_node(type, &node2))) { 1384 return (error); 1385 } 1386 1387 if ((error = ng_add_hook(node, name, &hook1))) { /* gives us a ref */ 1388 ng_rmnode(node2, NULL, NULL, 0); 1389 return (error); 1390 } 1391 1392 if ((error = ng_add_hook(node2, name2, &hook2))) { 1393 ng_rmnode(node2, NULL, NULL, 0); 1394 ng_destroy_hook(hook1); 1395 NG_HOOK_UNREF(hook1); 1396 return (error); 1397 } 1398 1399 /* 1400 * Actually link the two hooks together. 1401 */ 1402 hook1->hk_peer = hook2; 1403 hook2->hk_peer = hook1; 1404 1405 /* Each hook is referenced by the other */ 1406 NG_HOOK_REF(hook1); 1407 NG_HOOK_REF(hook2); 1408 1409 /* Give each node the opportunity to veto the pending connection */ 1410 if (hook1->hk_node->nd_type->connect) { 1411 error = (*hook1->hk_node->nd_type->connect) (hook1); 1412 } 1413 1414 if ((error == 0) && hook2->hk_node->nd_type->connect) { 1415 error = (*hook2->hk_node->nd_type->connect) (hook2); 1416 1417 } 1418 1419 /* 1420 * drop the references we were holding on the two hooks. 1421 */ 1422 if (error) { 1423 ng_destroy_hook(hook2); /* also zaps hook1 */ 1424 ng_rmnode(node2, NULL, NULL, 0); 1425 } else { 1426 /* As a last act, allow the hooks to be used */ 1427 hook1->hk_flags &= ~HK_INVALID; 1428 hook2->hk_flags &= ~HK_INVALID; 1429 } 1430 NG_HOOK_UNREF(hook1); 1431 NG_HOOK_UNREF(hook2); 1432 return (error); 1433} 1434 1435/************************************************************************ 1436 Utility routines to send self messages 1437************************************************************************/ 1438 1439/* Shut this node down as soon as everyone is clear of it */ 1440/* Should add arg "immediatly" to jump the queue */ 1441int 1442ng_rmnode_self(node_p node) 1443{ 1444 int error; 1445 1446 if (node == &ng_deadnode) 1447 return (0); 1448 node->nd_flags |= NGF_INVALID; 1449 if (node->nd_flags & NGF_CLOSING) 1450 return (0); 1451 1452 error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0); 1453 return (error); 1454} 1455 1456static void 1457ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) 1458{ 1459 ng_destroy_hook(hook); 1460 return ; 1461} 1462 1463int 1464ng_rmhook_self(hook_p hook) 1465{ 1466 int error; 1467 node_p node = NG_HOOK_NODE(hook); 1468 1469 if (node == &ng_deadnode) 1470 return (0); 1471 1472 error = ng_send_fn(node, hook, &ng_rmhook_part2, NULL, 0); 1473 return (error); 1474} 1475 1476/*********************************************************************** 1477 * Parse and verify a string of the form: <NODE:><PATH> 1478 * 1479 * Such a string can refer to a specific node or a specific hook 1480 * on a specific node, depending on how you look at it. In the 1481 * latter case, the PATH component must not end in a dot. 1482 * 1483 * Both <NODE:> and <PATH> are optional. The <PATH> is a string 1484 * of hook names separated by dots. This breaks out the original 1485 * string, setting *nodep to "NODE" (or NULL if none) and *pathp 1486 * to "PATH" (or NULL if degenerate). Also, *hookp will point to 1487 * the final hook component of <PATH>, if any, otherwise NULL. 1488 * 1489 * This returns -1 if the path is malformed. The char ** are optional. 1490 ***********************************************************************/ 1491int 1492ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp) 1493{ 1494 char *node, *path, *hook; 1495 int k; 1496 1497 /* 1498 * Extract absolute NODE, if any 1499 */ 1500 for (path = addr; *path && *path != ':'; path++); 1501 if (*path) { 1502 node = addr; /* Here's the NODE */ 1503 *path++ = '\0'; /* Here's the PATH */ 1504 1505 /* Node name must not be empty */ 1506 if (!*node) 1507 return -1; 1508 1509 /* A name of "." is OK; otherwise '.' not allowed */ 1510 if (strcmp(node, ".") != 0) { 1511 for (k = 0; node[k]; k++) 1512 if (node[k] == '.') 1513 return -1; 1514 } 1515 } else { 1516 node = NULL; /* No absolute NODE */ 1517 path = addr; /* Here's the PATH */ 1518 } 1519 1520 /* Snoop for illegal characters in PATH */ 1521 for (k = 0; path[k]; k++) 1522 if (path[k] == ':') 1523 return -1; 1524 1525 /* Check for no repeated dots in PATH */ 1526 for (k = 0; path[k]; k++) 1527 if (path[k] == '.' && path[k + 1] == '.') 1528 return -1; 1529 1530 /* Remove extra (degenerate) dots from beginning or end of PATH */ 1531 if (path[0] == '.') 1532 path++; 1533 if (*path && path[strlen(path) - 1] == '.') 1534 path[strlen(path) - 1] = 0; 1535 1536 /* If PATH has a dot, then we're not talking about a hook */ 1537 if (*path) { 1538 for (hook = path, k = 0; path[k]; k++) 1539 if (path[k] == '.') { 1540 hook = NULL; 1541 break; 1542 } 1543 } else 1544 path = hook = NULL; 1545 1546 /* Done */ 1547 if (nodep) 1548 *nodep = node; 1549 if (pathp) 1550 *pathp = path; 1551 if (hookp) 1552 *hookp = hook; 1553 return (0); 1554} 1555 1556/* 1557 * Given a path, which may be absolute or relative, and a starting node, 1558 * return the destination node. 1559 */ 1560int 1561ng_path2noderef(node_p here, const char *address, 1562 node_p *destp, hook_p *lasthook) 1563{ 1564 char fullpath[NG_PATHSIZ]; 1565 char *nodename, *path, pbuf[2]; 1566 node_p node, oldnode; 1567 char *cp; 1568 hook_p hook = NULL; 1569 1570 /* Initialize */ 1571 if (destp == NULL) { 1572 TRAP_ERROR(); 1573 return EINVAL; 1574 } 1575 *destp = NULL; 1576 1577 /* Make a writable copy of address for ng_path_parse() */ 1578 strncpy(fullpath, address, sizeof(fullpath) - 1); 1579 fullpath[sizeof(fullpath) - 1] = '\0'; 1580 1581 /* Parse out node and sequence of hooks */ 1582 if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) { 1583 TRAP_ERROR(); 1584 return EINVAL; 1585 } 1586 if (path == NULL) { 1587 pbuf[0] = '.'; /* Needs to be writable */ 1588 pbuf[1] = '\0'; 1589 path = pbuf; 1590 } 1591 1592 /* 1593 * For an absolute address, jump to the starting node. 1594 * Note that this holds a reference on the node for us. 1595 * Don't forget to drop the reference if we don't need it. 1596 */ 1597 if (nodename) { 1598 node = ng_name2noderef(here, nodename); 1599 if (node == NULL) { 1600 TRAP_ERROR(); 1601 return (ENOENT); 1602 } 1603 } else { 1604 if (here == NULL) { 1605 TRAP_ERROR(); 1606 return (EINVAL); 1607 } 1608 node = here; 1609 NG_NODE_REF(node); 1610 } 1611 1612 /* 1613 * Now follow the sequence of hooks 1614 * XXX 1615 * We actually cannot guarantee that the sequence 1616 * is not being demolished as we crawl along it 1617 * without extra-ordinary locking etc. 1618 * So this is a bit dodgy to say the least. 1619 * We can probably hold up some things by holding 1620 * the nodelist mutex for the time of this 1621 * crawl if we wanted.. At least that way we wouldn't have to 1622 * worry about the nodes dissappearing, but the hooks would still 1623 * be a problem. 1624 */ 1625 for (cp = path; node != NULL && *cp != '\0'; ) { 1626 char *segment; 1627 1628 /* 1629 * Break out the next path segment. Replace the dot we just 1630 * found with a NUL; "cp" points to the next segment (or the 1631 * NUL at the end). 1632 */ 1633 for (segment = cp; *cp != '\0'; cp++) { 1634 if (*cp == '.') { 1635 *cp++ = '\0'; 1636 break; 1637 } 1638 } 1639 1640 /* Empty segment */ 1641 if (*segment == '\0') 1642 continue; 1643 1644 /* We have a segment, so look for a hook by that name */ 1645 hook = ng_findhook(node, segment); 1646 1647 /* Can't get there from here... */ 1648 if (hook == NULL 1649 || NG_HOOK_PEER(hook) == NULL 1650 || NG_HOOK_NOT_VALID(hook) 1651 || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) { 1652 TRAP_ERROR(); 1653 NG_NODE_UNREF(node); 1654#if 0 1655 printf("hooknotvalid %s %s %d %d %d %d ", 1656 path, 1657 segment, 1658 hook == NULL, 1659 NG_HOOK_PEER(hook) == NULL, 1660 NG_HOOK_NOT_VALID(hook), 1661 NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))); 1662#endif 1663 return (ENOENT); 1664 } 1665 1666 /* 1667 * Hop on over to the next node 1668 * XXX 1669 * Big race conditions here as hooks and nodes go away 1670 * *** Idea.. store an ng_ID_t in each hook and use that 1671 * instead of the direct hook in this crawl? 1672 */ 1673 oldnode = node; 1674 if ((node = NG_PEER_NODE(hook))) 1675 NG_NODE_REF(node); /* XXX RACE */ 1676 NG_NODE_UNREF(oldnode); /* XXX another race */ 1677 if (NG_NODE_NOT_VALID(node)) { 1678 NG_NODE_UNREF(node); /* XXX more races */ 1679 node = NULL; 1680 } 1681 } 1682 1683 /* If node somehow missing, fail here (probably this is not needed) */ 1684 if (node == NULL) { 1685 TRAP_ERROR(); 1686 return (ENXIO); 1687 } 1688 1689 /* Done */ 1690 *destp = node; 1691 if (lasthook != NULL) 1692 *lasthook = (hook ? NG_HOOK_PEER(hook) : NULL); 1693 return (0); 1694} 1695 1696/***************************************************************\ 1697* Input queue handling. 1698* All activities are submitted to the node via the input queue 1699* which implements a multiple-reader/single-writer gate. 1700* Items which cannot be handled immeditly are queued. 1701* 1702* read-write queue locking inline functions * 1703\***************************************************************/ 1704 1705static __inline item_p ng_dequeue(struct ng_queue * ngq); 1706static __inline item_p ng_acquire_read(struct ng_queue * ngq, 1707 item_p item); 1708static __inline item_p ng_acquire_write(struct ng_queue * ngq, 1709 item_p item); 1710static __inline void ng_leave_read(struct ng_queue * ngq); 1711static __inline void ng_leave_write(struct ng_queue * ngq); 1712static __inline void ng_queue_rw(struct ng_queue * ngq, 1713 item_p item, int rw); 1714 1715/* 1716 * Definition of the bits fields in the ng_queue flag word. 1717 * Defined here rather than in netgraph.h because no-one should fiddle 1718 * with them. 1719 * 1720 * The ordering here may be important! don't shuffle these. 1721 */ 1722/*- 1723 Safety Barrier--------+ (adjustable to suit taste) (not used yet) 1724 | 1725 V 1726+-------+-------+-------+-------+-------+-------+-------+-------+ 1727| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1728| |A|c|t|i|v|e| |R|e|a|d|e|r| |C|o|u|n|t| | | | | | | | | |R|A|W| 1729| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |P|W|P| 1730+-------+-------+-------+-------+-------+-------+-------+-------+ 1731\___________________________ ____________________________/ | | | 1732 V | | | 1733 [active reader count] | | | 1734 | | | 1735 Read Pending ------------------------------------+ | | 1736 | | 1737 Active Writer -------------------------------------+ | 1738 | 1739 Write Pending ---------------------------------------+ 1740 1741 1742*/ 1743#define WRITE_PENDING 0x00000001 1744#define WRITER_ACTIVE 0x00000002 1745#define READ_PENDING 0x00000004 1746#define READER_INCREMENT 0x00000008 1747#define READER_MASK 0xfffffff0 /* Not valid if WRITER_ACTIVE is set */ 1748#define SAFETY_BARRIER 0x00100000 /* 64K items queued should be enough */ 1749 1750/* Defines of more elaborate states on the queue */ 1751/* Mask of bits a read cares about */ 1752#define NGQ_RMASK (WRITE_PENDING|WRITER_ACTIVE|READ_PENDING) 1753 1754/* Mask of bits a write cares about */ 1755#define NGQ_WMASK (NGQ_RMASK|READER_MASK) 1756 1757/* tests to decide if we could get a read or write off the queue */ 1758#define CAN_GET_READ(flag) ((flag & NGQ_RMASK) == READ_PENDING) 1759#define CAN_GET_WRITE(flag) ((flag & NGQ_WMASK) == WRITE_PENDING) 1760 1761/* Is there a chance of getting ANY work off the queue? */ 1762#define CAN_GET_WORK(flag) (CAN_GET_READ(flag) || CAN_GET_WRITE(flag)) 1763 1764/* 1765 * Taking into account the current state of the queue and node, possibly take 1766 * the next entry off the queue and return it. Return NULL if there was 1767 * nothing we could return, either because there really was nothing there, or 1768 * because the node was in a state where it cannot yet process the next item 1769 * on the queue. 1770 * 1771 * This MUST MUST MUST be called with the mutex held. 1772 */ 1773static __inline item_p 1774ng_dequeue(struct ng_queue *ngq) 1775{ 1776 item_p item; 1777 u_int add_arg; 1778 1779 mtx_assert(&ngq->q_mtx, MA_OWNED); 1780 1781 if (CAN_GET_READ(ngq->q_flags)) { 1782 /* 1783 * Head of queue is a reader and we have no write active. 1784 * We don't care how many readers are already active. 1785 * Adjust the flags for the item we are about to dequeue. 1786 * Add the correct increment for the reader count as well. 1787 */ 1788 add_arg = (READER_INCREMENT - READ_PENDING); 1789 } else if (CAN_GET_WRITE(ngq->q_flags)) { 1790 /* 1791 * There is a pending write, no readers and no active writer. 1792 * This means we can go ahead with the pending writer. Note 1793 * the fact that we now have a writer, ready for when we take 1794 * it off the queue. 1795 * 1796 * We don't need to worry about a possible collision with the 1797 * fasttrack reader. 1798 * 1799 * The fasttrack thread may take a long time to discover that we 1800 * are running so we would have an inconsistent state in the 1801 * flags for a while. Since we ignore the reader count 1802 * entirely when the WRITER_ACTIVE flag is set, this should 1803 * not matter (in fact it is defined that way). If it tests 1804 * the flag before this operation, the WRITE_PENDING flag 1805 * will make it fail, and if it tests it later, the 1806 * WRITER_ACTIVE flag will do the same. If it is SO slow that 1807 * we have actually completed the operation, and neither flag 1808 * is set (nor the READ_PENDING) by the time that it tests 1809 * the flags, then it is actually ok for it to continue. If 1810 * it completes and we've finished and the read pending is 1811 * set it still fails. 1812 * 1813 * So we can just ignore it, as long as we can ensure that the 1814 * transition from WRITE_PENDING state to the WRITER_ACTIVE 1815 * state is atomic. 1816 * 1817 * After failing, first it will be held back by the mutex, then 1818 * when it can proceed, it will queue its request, then it 1819 * would arrive at this function. Usually it will have to 1820 * leave empty handed because the ACTIVE WRITER bit will be 1821 * set. 1822 * 1823 * Adjust the flags for the item we are about to dequeue 1824 * and for the new active writer. 1825 */ 1826 add_arg = (WRITER_ACTIVE - WRITE_PENDING); 1827 /* 1828 * We want to write "active writer, no readers " Now go make 1829 * it true. In fact there may be a number in the readers 1830 * count but we know it is not true and will be fixed soon. 1831 * We will fix the flags for the next pending entry in a 1832 * moment. 1833 */ 1834 } else { 1835 /* 1836 * We can't dequeue anything.. return and say so. Probably we 1837 * have a write pending and the readers count is non zero. If 1838 * we got here because a reader hit us just at the wrong 1839 * moment with the fasttrack code, and put us in a strange 1840 * state, then it will be through in just a moment, (as soon 1841 * as we release the mutex) and keep things moving. 1842 * Make sure we remove ourselves from the work queue. 1843 */ 1844 ng_worklist_remove(ngq->q_node); 1845 return (0); 1846 } 1847 1848 /* 1849 * Now we dequeue the request (whatever it may be) and correct the 1850 * pending flags and the next and last pointers. 1851 */ 1852 item = ngq->queue; 1853 ngq->queue = item->el_next; 1854 if (ngq->last == &(item->el_next)) { 1855 /* 1856 * that was the last entry in the queue so set the 'last 1857 * pointer up correctly and make sure the pending flags are 1858 * clear. 1859 */ 1860 ngq->last = &(ngq->queue); 1861 /* 1862 * Whatever flag was set will be cleared and 1863 * the new acive field will be set by the add as well, 1864 * so we don't need to change add_arg. 1865 * But we know we don't need to be on the work list. 1866 */ 1867 atomic_add_long(&ngq->q_flags, add_arg); 1868 ng_worklist_remove(ngq->q_node); 1869 } else { 1870 /* 1871 * Since there is something on the queue, note what it is 1872 * in the flags word. 1873 */ 1874 if ((ngq->queue->el_flags & NGQF_RW) == NGQF_READER) { 1875 add_arg += READ_PENDING; 1876 } else { 1877 add_arg += WRITE_PENDING; 1878 } 1879 atomic_add_long(&ngq->q_flags, add_arg); 1880 /* 1881 * If we see more doable work, make sure we are 1882 * on the work queue. 1883 */ 1884 if (CAN_GET_WORK(ngq->q_flags)) { 1885 ng_setisr(ngq->q_node); 1886 } 1887 } 1888 /* 1889 * We have successfully cleared the old pending flag, set the new one 1890 * if it is needed, and incremented the appropriate active field. 1891 * (all in one atomic addition.. ) 1892 */ 1893 return (item); 1894} 1895 1896/* 1897 * Queue a packet to be picked up by someone else. 1898 * We really don't care who, but we can't or don't want to hang around 1899 * to process it ourselves. We are probably an interrupt routine.. 1900 * 1 = writer, 0 = reader 1901 */ 1902#define NGQRW_R 0 1903#define NGQRW_W 1 1904static __inline void 1905ng_queue_rw(struct ng_queue * ngq, item_p item, int rw) 1906{ 1907 mtx_assert(&ngq->q_mtx, MA_OWNED); 1908 1909 item->el_next = NULL; /* maybe not needed */ 1910 *ngq->last = item; 1911 /* 1912 * If it was the first item in the queue then we need to 1913 * set the last pointer and the type flags. 1914 */ 1915 if (ngq->last == &(ngq->queue)) { 1916 /* 1917 * When called with constants for rw, the optimiser will 1918 * remove the unneeded branch below. 1919 */ 1920 if (rw == NGQRW_W) { 1921 atomic_add_long(&ngq->q_flags, WRITE_PENDING); 1922 } else { 1923 atomic_add_long(&ngq->q_flags, READ_PENDING); 1924 } 1925 } 1926 ngq->last = &(item->el_next); 1927} 1928 1929 1930/* 1931 * This function 'cheats' in that it first tries to 'grab' the use of the 1932 * node, without going through the mutex. We can do this becasue of the 1933 * semantics of the lock. The semantics include a clause that says that the 1934 * value of the readers count is invalid if the WRITER_ACTIVE flag is set. It 1935 * also says that the WRITER_ACTIVE flag cannot be set if the readers count 1936 * is not zero. Note that this talks about what is valid to SET the 1937 * WRITER_ACTIVE flag, because from the moment it is set, the value if the 1938 * reader count is immaterial, and not valid. The two 'pending' flags have a 1939 * similar effect, in that If they are orthogonal to the two active fields in 1940 * how they are set, but if either is set, the attempted 'grab' need to be 1941 * backed out because there is earlier work, and we maintain ordering in the 1942 * queue. The result of this is that the reader request can try obtain use of 1943 * the node with only a single atomic addition, and without any of the mutex 1944 * overhead. If this fails the operation degenerates to the same as for other 1945 * cases. 1946 * 1947 */ 1948static __inline item_p 1949ng_acquire_read(struct ng_queue *ngq, item_p item) 1950{ 1951 1952 /* ######### Hack alert ######### */ 1953 atomic_add_long(&ngq->q_flags, READER_INCREMENT); 1954 if ((ngq->q_flags & NGQ_RMASK) == 0) { 1955 /* Successfully grabbed node */ 1956 return (item); 1957 } 1958 /* undo the damage if we didn't succeed */ 1959 atomic_subtract_long(&ngq->q_flags, READER_INCREMENT); 1960 1961 /* ######### End Hack alert ######### */ 1962 mtx_lock_spin((&ngq->q_mtx)); 1963 /* 1964 * Try again. Another processor (or interrupt for that matter) may 1965 * have removed the last queued item that was stopping us from 1966 * running, between the previous test, and the moment that we took 1967 * the mutex. (Or maybe a writer completed.) 1968 */ 1969 if ((ngq->q_flags & NGQ_RMASK) == 0) { 1970 atomic_add_long(&ngq->q_flags, READER_INCREMENT); 1971 mtx_unlock_spin((&ngq->q_mtx)); 1972 return (item); 1973 } 1974 1975 /* 1976 * and queue the request for later. 1977 */ 1978 item->el_flags |= NGQF_READER; 1979 ng_queue_rw(ngq, item, NGQRW_R); 1980 1981 /* 1982 * Ok, so that's the item successfully queued for later. So now we 1983 * see if we can dequeue something to run instead. 1984 */ 1985 item = ng_dequeue(ngq); 1986 mtx_unlock_spin(&(ngq->q_mtx)); 1987 return (item); 1988} 1989 1990static __inline item_p 1991ng_acquire_write(struct ng_queue *ngq, item_p item) 1992{ 1993restart: 1994 mtx_lock_spin(&(ngq->q_mtx)); 1995 /* 1996 * If there are no readers, no writer, and no pending packets, then 1997 * we can just go ahead. In all other situations we need to queue the 1998 * request 1999 */ 2000 if ((ngq->q_flags & NGQ_WMASK) == 0) { 2001 atomic_add_long(&ngq->q_flags, WRITER_ACTIVE); 2002 mtx_unlock_spin((&ngq->q_mtx)); 2003 if (ngq->q_flags & READER_MASK) { 2004 /* Collision with fast-track reader */ 2005 atomic_subtract_long(&ngq->q_flags, WRITER_ACTIVE); 2006 goto restart; 2007 } 2008 return (item); 2009 } 2010 2011 /* 2012 * and queue the request for later. 2013 */ 2014 item->el_flags &= ~NGQF_RW; 2015 ng_queue_rw(ngq, item, NGQRW_W); 2016 2017 /* 2018 * Ok, so that's the item successfully queued for later. So now we 2019 * see if we can dequeue something to run instead. 2020 */ 2021 item = ng_dequeue(ngq); 2022 mtx_unlock_spin(&(ngq->q_mtx)); 2023 return (item); 2024} 2025 2026static __inline void 2027ng_leave_read(struct ng_queue *ngq) 2028{ 2029 atomic_subtract_long(&ngq->q_flags, READER_INCREMENT); 2030} 2031 2032static __inline void 2033ng_leave_write(struct ng_queue *ngq) 2034{ 2035 atomic_subtract_long(&ngq->q_flags, WRITER_ACTIVE); 2036} 2037 2038static void 2039ng_flush_input_queue(struct ng_queue * ngq) 2040{ 2041 item_p item; 2042 u_int add_arg; 2043 mtx_lock_spin(&ngq->q_mtx); 2044 for (;;) { 2045 /* Now take a look at what's on the queue */ 2046 if (ngq->q_flags & READ_PENDING) { 2047 add_arg = -READ_PENDING; 2048 } else if (ngq->q_flags & WRITE_PENDING) { 2049 add_arg = -WRITE_PENDING; 2050 } else { 2051 break; 2052 } 2053 2054 item = ngq->queue; 2055 ngq->queue = item->el_next; 2056 if (ngq->last == &(item->el_next)) { 2057 ngq->last = &(ngq->queue); 2058 } else { 2059 if ((ngq->queue->el_flags & NGQF_RW) == NGQF_READER) { 2060 add_arg += READ_PENDING; 2061 } else { 2062 add_arg += WRITE_PENDING; 2063 } 2064 } 2065 atomic_add_long(&ngq->q_flags, add_arg); 2066 2067 mtx_unlock_spin(&ngq->q_mtx); 2068 NG_FREE_ITEM(item); 2069 mtx_lock_spin(&ngq->q_mtx); 2070 } 2071 /* 2072 * Take us off the work queue if we are there. 2073 * We definatly have no work to be done. 2074 */ 2075 ng_worklist_remove(ngq->q_node); 2076 mtx_unlock_spin(&ngq->q_mtx); 2077} 2078 2079/*********************************************************************** 2080* Externally visible method for sending or queueing messages or data. 2081***********************************************************************/ 2082 2083/* 2084 * The module code should have filled out the item correctly by this stage: 2085 * Common: 2086 * reference to destination node. 2087 * Reference to destination rcv hook if relevant. 2088 * Data: 2089 * pointer to mbuf 2090 * Control_Message: 2091 * pointer to msg. 2092 * ID of original sender node. (return address) 2093 * Function: 2094 * Function pointer 2095 * void * argument 2096 * integer argument 2097 * 2098 * The nodes have several routines and macros to help with this task: 2099 */ 2100 2101int 2102ng_snd_item(item_p item, int queue) 2103{ 2104 hook_p hook = NGI_HOOK(item); 2105 node_p node = NGI_NODE(item); 2106 int rw; 2107 int error = 0, ierror; 2108 item_p oitem; 2109 struct ng_queue * ngq = &node->nd_input_queue; 2110 2111#ifdef NETGRAPH_DEBUG 2112 _ngi_check(item, __FILE__, __LINE__); 2113#endif 2114 2115 if (item == NULL) { 2116 TRAP_ERROR(); 2117 return (EINVAL); /* failed to get queue element */ 2118 } 2119 if (node == NULL) { 2120 NG_FREE_ITEM(item); 2121 TRAP_ERROR(); 2122 return (EINVAL); /* No address */ 2123 } 2124 switch(item->el_flags & NGQF_TYPE) { 2125 case NGQF_DATA: 2126 /* 2127 * DATA MESSAGE 2128 * Delivered to a node via a non-optional hook. 2129 * Both should be present in the item even though 2130 * the node is derivable from the hook. 2131 * References are held on both by the item. 2132 */ 2133 2134 /* Protect nodes from sending NULL pointers 2135 * to each other 2136 */ 2137 if (NGI_M(item) == NULL) 2138 return (EINVAL); 2139 2140 CHECK_DATA_MBUF(NGI_M(item)); 2141 if (hook == NULL) { 2142 NG_FREE_ITEM(item); 2143 TRAP_ERROR(); 2144 return(EINVAL); 2145 } 2146 if ((NG_HOOK_NOT_VALID(hook)) 2147 || (NG_NODE_NOT_VALID(NG_HOOK_NODE(hook)))) { 2148 NG_FREE_ITEM(item); 2149 return (ENOTCONN); 2150 } 2151 if ((hook->hk_flags & HK_QUEUE)) { 2152 queue = 1; 2153 } 2154 /* By default data is a reader in the locking scheme */ 2155 item->el_flags |= NGQF_READER; 2156 rw = NGQRW_R; 2157 break; 2158 case NGQF_MESG: 2159 /* 2160 * CONTROL MESSAGE 2161 * Delivered to a node. 2162 * Hook is optional. 2163 * References are held by the item on the node and 2164 * the hook if it is present. 2165 */ 2166 if (hook && (hook->hk_flags & HK_QUEUE)) { 2167 queue = 1; 2168 } 2169 /* Data messages count as writers unles explicitly exempted */ 2170 if (NGI_MSG(item)->header.cmd & NGM_READONLY) { 2171 item->el_flags |= NGQF_READER; 2172 rw = NGQRW_R; 2173 } else { 2174 item->el_flags &= ~NGQF_RW; 2175 rw = NGQRW_W; 2176 } 2177 break; 2178 case NGQF_FN: 2179 item->el_flags &= ~NGQF_RW; 2180 rw = NGQRW_W; 2181 break; 2182 default: 2183 NG_FREE_ITEM(item); 2184 TRAP_ERROR(); 2185 return (EINVAL); 2186 } 2187 /* 2188 * If the node specifies single threading, force writer semantics 2189 * Similarly the node may say one hook always produces writers. 2190 * These are over-rides. 2191 */ 2192 if ((node->nd_flags & NGF_FORCE_WRITER) 2193 || (hook && (hook->hk_flags & HK_FORCE_WRITER))) { 2194 rw = NGQRW_W; 2195 item->el_flags &= ~NGQF_READER; 2196 } 2197 if (queue) { 2198 /* Put it on the queue for that node*/ 2199#ifdef NETGRAPH_DEBUG 2200 _ngi_check(item, __FILE__, __LINE__); 2201#endif 2202 mtx_lock_spin(&(ngq->q_mtx)); 2203 ng_queue_rw(ngq, item, rw); 2204 /* 2205 * If there are active elements then we can rely on 2206 * them. if not we should not rely on another packet 2207 * coming here by another path, 2208 * so it is best to put us in the netisr list. 2209 * We can take the worklist lock with the node locked 2210 * BUT NOT THE REVERSE! 2211 */ 2212 if (CAN_GET_WORK(ngq->q_flags)) { 2213 ng_setisr(node); 2214 } 2215 mtx_unlock_spin(&(ngq->q_mtx)); 2216 return (0); 2217 } 2218 /* 2219 * Take a queue item and a node and see if we can apply the item to 2220 * the node. We may end up getting a different item to apply instead. 2221 * Will allow for a piggyback reply only in the case where 2222 * there is no queueing. 2223 */ 2224 2225 oitem = item; 2226 /* 2227 * We already decided how we will be queueud or treated. 2228 * Try get the appropriate operating permission. 2229 */ 2230 if (rw == NGQRW_R) { 2231 item = ng_acquire_read(ngq, item); 2232 } else { 2233 item = ng_acquire_write(ngq, item); 2234 } 2235 2236 /* 2237 * May have come back with a different item. 2238 * or maybe none at all. The one we started with will 2239 * have been queued in thises cases. 2240 */ 2241 if (item == NULL) { 2242 return (0); 2243 } 2244 2245#ifdef NETGRAPH_DEBUG 2246 _ngi_check(item, __FILE__, __LINE__); 2247#endif 2248 /* 2249 * Take over the reference frm the item. 2250 * Hold it until the called function returns. 2251 */ 2252 NGI_GET_NODE(item, node); /* zaps stored node */ 2253 2254 ierror = ng_apply_item(node, item); /* drops r/w lock when done */ 2255 2256 /* only return an error if it was our initial item.. (compat hack) */ 2257 if (oitem == item) { 2258 error = ierror; 2259 } 2260 2261 /* 2262 * If the node goes away when we remove the reference, 2263 * whatever we just did caused it.. whatever we do, DO NOT 2264 * access the node again! 2265 */ 2266 if (NG_NODE_UNREF(node) == 0) { 2267 return (error); 2268 } 2269 2270 /* 2271 * Now we've handled the packet we brought, (or a friend of it) let's 2272 * look for any other packets that may have been queued up. We hold 2273 * no locks, so if someone puts something in the queue after 2274 * we check that it is empty, it is their problem 2275 * to ensure it is processed. If we have the netisr thread cme in here 2276 * while we still say we have stuff to do, we may get a boost 2277 * in SMP systems. :-) 2278 */ 2279 for (;;) { 2280 /* 2281 * dequeue acquires and adjusts the input_queue as it dequeues 2282 * packets. It acquires the rw lock as needed. 2283 */ 2284 mtx_lock_spin(&ngq->q_mtx); 2285 item = ng_dequeue(ngq); /* fixes worklist too*/ 2286 if (!item) { 2287 mtx_unlock_spin(&ngq->q_mtx); 2288 return (error); 2289 } 2290 mtx_unlock_spin(&ngq->q_mtx); 2291 2292 /* 2293 * Take over the reference frm the item. 2294 * Hold it until the called function returns. 2295 */ 2296 2297 NGI_GET_NODE(item, node); /* zaps stored node */ 2298 2299 /* 2300 * We have the appropriate lock, so run the item. 2301 * When finished it will drop the lock accordingly 2302 */ 2303 ierror = ng_apply_item(node, item); 2304 2305 /* 2306 * only return an error if it was our initial 2307 * item.. (compat hack) 2308 */ 2309 if (oitem == item) { 2310 error = ierror; 2311 } 2312 2313 /* 2314 * If the node goes away when we remove the reference, 2315 * whatever we just did caused it.. whatever we do, DO NOT 2316 * access the node again! 2317 */ 2318 if (NG_NODE_UNREF(node) == 0) { 2319 break; 2320 } 2321 } 2322 return (error); 2323} 2324 2325/* 2326 * We have an item that was possibly queued somewhere. 2327 * It should contain all the information needed 2328 * to run it on the appropriate node/hook. 2329 */ 2330static int 2331ng_apply_item(node_p node, item_p item) 2332{ 2333 hook_p hook; 2334 int was_reader = ((item->el_flags & NGQF_RW)); 2335 int error = 0; 2336 ng_rcvdata_t *rcvdata; 2337 ng_rcvmsg_t *rcvmsg; 2338 2339 NGI_GET_HOOK(item, hook); /* clears stored hook */ 2340#ifdef NETGRAPH_DEBUG 2341 _ngi_check(item, __FILE__, __LINE__); 2342#endif 2343 switch (item->el_flags & NGQF_TYPE) { 2344 case NGQF_DATA: 2345 /* 2346 * Check things are still ok as when we were queued. 2347 */ 2348 if ((hook == NULL) 2349 || NG_HOOK_NOT_VALID(hook) 2350 || NG_NODE_NOT_VALID(node) ) { 2351 error = EIO; 2352 NG_FREE_ITEM(item); 2353 break; 2354 } 2355 /* 2356 * If no receive method, just silently drop it. 2357 * Give preference to the hook over-ride method 2358 */ 2359 if ((!(rcvdata = hook->hk_rcvdata)) 2360 && (!(rcvdata = NG_HOOK_NODE(hook)->nd_type->rcvdata))) { 2361 error = 0; 2362 NG_FREE_ITEM(item); 2363 break; 2364 } 2365 error = (*rcvdata)(hook, item); 2366 break; 2367 case NGQF_MESG: 2368 if (hook) { 2369 if (NG_HOOK_NOT_VALID(hook)) { 2370 /* 2371 * The hook has been zapped then we can't 2372 * use it. Immediatly drop its reference. 2373 * The message may not need it. 2374 */ 2375 NG_HOOK_UNREF(hook); 2376 hook = NULL; 2377 } 2378 } 2379 /* 2380 * Similarly, if the node is a zombie there is 2381 * nothing we can do with it, drop everything. 2382 */ 2383 if (NG_NODE_NOT_VALID(node)) { 2384 TRAP_ERROR(); 2385 error = EINVAL; 2386 NG_FREE_ITEM(item); 2387 } else { 2388 /* 2389 * Call the appropriate message handler for the object. 2390 * It is up to the message handler to free the message. 2391 * If it's a generic message, handle it generically, 2392 * otherwise call the type's message handler 2393 * (if it exists) 2394 * XXX (race). Remember that a queued message may 2395 * reference a node or hook that has just been 2396 * invalidated. It will exist as the queue code 2397 * is holding a reference, but.. 2398 */ 2399 2400 struct ng_mesg *msg = NGI_MSG(item); 2401 2402 /* 2403 * check if the generic handler owns it. 2404 */ 2405 if ((msg->header.typecookie == NGM_GENERIC_COOKIE) 2406 && ((msg->header.flags & NGF_RESP) == 0)) { 2407 error = ng_generic_msg(node, item, hook); 2408 break; 2409 } 2410 /* 2411 * Now see if there is a handler (hook or node specific) 2412 * in the target node. If none, silently discard. 2413 */ 2414 if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) 2415 && (!(rcvmsg = node->nd_type->rcvmsg))) { 2416 TRAP_ERROR(); 2417 error = 0; 2418 NG_FREE_ITEM(item); 2419 break; 2420 } 2421 error = (*rcvmsg)(node, item, hook); 2422 } 2423 break; 2424 case NGQF_FN: 2425 /* 2426 * We have to implicitly trust the hook, 2427 * as some of these are used for system purposes 2428 * where the hook is invalid. In the case of 2429 * the shutdown message we allow it to hit 2430 * even if the node is invalid. 2431 */ 2432 if ((NG_NODE_NOT_VALID(node)) 2433 && (NGI_FN(item) != &ng_rmnode)) { 2434 TRAP_ERROR(); 2435 error = EINVAL; 2436 break; 2437 } 2438 (*NGI_FN(item))(node, hook, NGI_ARG1(item), NGI_ARG2(item)); 2439 NG_FREE_ITEM(item); 2440 break; 2441 2442 } 2443 /* 2444 * We held references on some of the resources 2445 * that we took from the item. Now that we have 2446 * finished doing everything, drop those references. 2447 */ 2448 if (hook) { 2449 NG_HOOK_UNREF(hook); 2450 } 2451 2452 if (was_reader) { 2453 ng_leave_read(&node->nd_input_queue); 2454 } else { 2455 ng_leave_write(&node->nd_input_queue); 2456 } 2457 return (error); 2458} 2459 2460/*********************************************************************** 2461 * Implement the 'generic' control messages 2462 ***********************************************************************/ 2463static int 2464ng_generic_msg(node_p here, item_p item, hook_p lasthook) 2465{ 2466 int error = 0; 2467 struct ng_mesg *msg; 2468 struct ng_mesg *resp = NULL; 2469 2470 NGI_GET_MSG(item, msg); 2471 if (msg->header.typecookie != NGM_GENERIC_COOKIE) { 2472 TRAP_ERROR(); 2473 error = EINVAL; 2474 goto out; 2475 } 2476 switch (msg->header.cmd) { 2477 case NGM_SHUTDOWN: 2478 ng_rmnode(here, NULL, NULL, 0); 2479 break; 2480 case NGM_MKPEER: 2481 { 2482 struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; 2483 2484 if (msg->header.arglen != sizeof(*mkp)) { 2485 TRAP_ERROR(); 2486 error = EINVAL; 2487 break; 2488 } 2489 mkp->type[sizeof(mkp->type) - 1] = '\0'; 2490 mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0'; 2491 mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0'; 2492 error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type); 2493 break; 2494 } 2495 case NGM_CONNECT: 2496 { 2497 struct ngm_connect *const con = 2498 (struct ngm_connect *) msg->data; 2499 node_p node2; 2500 2501 if (msg->header.arglen != sizeof(*con)) { 2502 TRAP_ERROR(); 2503 error = EINVAL; 2504 break; 2505 } 2506 con->path[sizeof(con->path) - 1] = '\0'; 2507 con->ourhook[sizeof(con->ourhook) - 1] = '\0'; 2508 con->peerhook[sizeof(con->peerhook) - 1] = '\0'; 2509 /* Don't forget we get a reference.. */ 2510 error = ng_path2noderef(here, con->path, &node2, NULL); 2511 if (error) 2512 break; 2513 error = ng_con_nodes(here, con->ourhook, node2, con->peerhook); 2514 NG_NODE_UNREF(node2); 2515 break; 2516 } 2517 case NGM_NAME: 2518 { 2519 struct ngm_name *const nam = (struct ngm_name *) msg->data; 2520 2521 if (msg->header.arglen != sizeof(*nam)) { 2522 TRAP_ERROR(); 2523 error = EINVAL; 2524 break; 2525 } 2526 nam->name[sizeof(nam->name) - 1] = '\0'; 2527 error = ng_name_node(here, nam->name); 2528 break; 2529 } 2530 case NGM_RMHOOK: 2531 { 2532 struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data; 2533 hook_p hook; 2534 2535 if (msg->header.arglen != sizeof(*rmh)) { 2536 TRAP_ERROR(); 2537 error = EINVAL; 2538 break; 2539 } 2540 rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0'; 2541 if ((hook = ng_findhook(here, rmh->ourhook)) != NULL) 2542 ng_destroy_hook(hook); 2543 break; 2544 } 2545 case NGM_NODEINFO: 2546 { 2547 struct nodeinfo *ni; 2548 2549 NG_MKRESPONSE(resp, msg, sizeof(*ni), M_NOWAIT); 2550 if (resp == NULL) { 2551 error = ENOMEM; 2552 break; 2553 } 2554 2555 /* Fill in node info */ 2556 ni = (struct nodeinfo *) resp->data; 2557 if (NG_NODE_HAS_NAME(here)) 2558 strcpy(ni->name, NG_NODE_NAME(here)); 2559 strcpy(ni->type, here->nd_type->name); 2560 ni->id = ng_node2ID(here); 2561 ni->hooks = here->nd_numhooks; 2562 break; 2563 } 2564 case NGM_LISTHOOKS: 2565 { 2566 const int nhooks = here->nd_numhooks; 2567 struct hooklist *hl; 2568 struct nodeinfo *ni; 2569 hook_p hook; 2570 2571 /* Get response struct */ 2572 NG_MKRESPONSE(resp, msg, sizeof(*hl) 2573 + (nhooks * sizeof(struct linkinfo)), M_NOWAIT); 2574 if (resp == NULL) { 2575 error = ENOMEM; 2576 break; 2577 } 2578 hl = (struct hooklist *) resp->data; 2579 ni = &hl->nodeinfo; 2580 2581 /* Fill in node info */ 2582 if (NG_NODE_HAS_NAME(here)) 2583 strcpy(ni->name, NG_NODE_NAME(here)); 2584 strcpy(ni->type, here->nd_type->name); 2585 ni->id = ng_node2ID(here); 2586 2587 /* Cycle through the linked list of hooks */ 2588 ni->hooks = 0; 2589 LIST_FOREACH(hook, &here->nd_hooks, hk_hooks) { 2590 struct linkinfo *const link = &hl->link[ni->hooks]; 2591 2592 if (ni->hooks >= nhooks) { 2593 log(LOG_ERR, "%s: number of %s changed\n", 2594 __func__, "hooks"); 2595 break; 2596 } 2597 if (NG_HOOK_NOT_VALID(hook)) 2598 continue; 2599 strcpy(link->ourhook, NG_HOOK_NAME(hook)); 2600 strcpy(link->peerhook, NG_PEER_HOOK_NAME(hook)); 2601 if (NG_PEER_NODE_NAME(hook)[0] != '\0') 2602 strcpy(link->nodeinfo.name, 2603 NG_PEER_NODE_NAME(hook)); 2604 strcpy(link->nodeinfo.type, 2605 NG_PEER_NODE(hook)->nd_type->name); 2606 link->nodeinfo.id = ng_node2ID(NG_PEER_NODE(hook)); 2607 link->nodeinfo.hooks = NG_PEER_NODE(hook)->nd_numhooks; 2608 ni->hooks++; 2609 } 2610 break; 2611 } 2612 2613 case NGM_LISTNAMES: 2614 case NGM_LISTNODES: 2615 { 2616 const int unnamed = (msg->header.cmd == NGM_LISTNODES); 2617 struct namelist *nl; 2618 node_p node; 2619 int num = 0; 2620 2621 mtx_lock(&ng_nodelist_mtx); 2622 /* Count number of nodes */ 2623 LIST_FOREACH(node, &ng_nodelist, nd_nodes) { 2624 if (NG_NODE_IS_VALID(node) 2625 && (unnamed || NG_NODE_HAS_NAME(node))) { 2626 num++; 2627 } 2628 } 2629 mtx_unlock(&ng_nodelist_mtx); 2630 2631 /* Get response struct */ 2632 NG_MKRESPONSE(resp, msg, sizeof(*nl) 2633 + (num * sizeof(struct nodeinfo)), M_NOWAIT); 2634 if (resp == NULL) { 2635 error = ENOMEM; 2636 break; 2637 } 2638 nl = (struct namelist *) resp->data; 2639 2640 /* Cycle through the linked list of nodes */ 2641 nl->numnames = 0; 2642 mtx_lock(&ng_nodelist_mtx); 2643 LIST_FOREACH(node, &ng_nodelist, nd_nodes) { 2644 struct nodeinfo *const np = &nl->nodeinfo[nl->numnames]; 2645 2646 if (nl->numnames >= num) { 2647 log(LOG_ERR, "%s: number of %s changed\n", 2648 __func__, "nodes"); 2649 break; 2650 } 2651 if (NG_NODE_NOT_VALID(node)) 2652 continue; 2653 if (!unnamed && (! NG_NODE_HAS_NAME(node))) 2654 continue; 2655 if (NG_NODE_HAS_NAME(node)) 2656 strcpy(np->name, NG_NODE_NAME(node)); 2657 strcpy(np->type, node->nd_type->name); 2658 np->id = ng_node2ID(node); 2659 np->hooks = node->nd_numhooks; 2660 nl->numnames++; 2661 } 2662 mtx_unlock(&ng_nodelist_mtx); 2663 break; 2664 } 2665 2666 case NGM_LISTTYPES: 2667 { 2668 struct typelist *tl; 2669 struct ng_type *type; 2670 int num = 0; 2671 2672 mtx_lock(&ng_typelist_mtx); 2673 /* Count number of types */ 2674 LIST_FOREACH(type, &ng_typelist, types) { 2675 num++; 2676 } 2677 mtx_unlock(&ng_typelist_mtx); 2678 2679 /* Get response struct */ 2680 NG_MKRESPONSE(resp, msg, sizeof(*tl) 2681 + (num * sizeof(struct typeinfo)), M_NOWAIT); 2682 if (resp == NULL) { 2683 error = ENOMEM; 2684 break; 2685 } 2686 tl = (struct typelist *) resp->data; 2687 2688 /* Cycle through the linked list of types */ 2689 tl->numtypes = 0; 2690 mtx_lock(&ng_typelist_mtx); 2691 LIST_FOREACH(type, &ng_typelist, types) { 2692 struct typeinfo *const tp = &tl->typeinfo[tl->numtypes]; 2693 2694 if (tl->numtypes >= num) { 2695 log(LOG_ERR, "%s: number of %s changed\n", 2696 __func__, "types"); 2697 break; 2698 } 2699 strcpy(tp->type_name, type->name); 2700 tp->numnodes = type->refs - 1; /* don't count list */ 2701 tl->numtypes++; 2702 } 2703 mtx_unlock(&ng_typelist_mtx); 2704 break; 2705 } 2706 2707 case NGM_BINARY2ASCII: 2708 { 2709 int bufSize = 20 * 1024; /* XXX hard coded constant */ 2710 const struct ng_parse_type *argstype; 2711 const struct ng_cmdlist *c; 2712 struct ng_mesg *binary, *ascii; 2713 2714 /* Data area must contain a valid netgraph message */ 2715 binary = (struct ng_mesg *)msg->data; 2716 if (msg->header.arglen < sizeof(struct ng_mesg) 2717 || (msg->header.arglen - sizeof(struct ng_mesg) 2718 < binary->header.arglen)) { 2719 TRAP_ERROR(); 2720 error = EINVAL; 2721 break; 2722 } 2723 2724 /* Get a response message with lots of room */ 2725 NG_MKRESPONSE(resp, msg, sizeof(*ascii) + bufSize, M_NOWAIT); 2726 if (resp == NULL) { 2727 error = ENOMEM; 2728 break; 2729 } 2730 ascii = (struct ng_mesg *)resp->data; 2731 2732 /* Copy binary message header to response message payload */ 2733 bcopy(binary, ascii, sizeof(*binary)); 2734 2735 /* Find command by matching typecookie and command number */ 2736 for (c = here->nd_type->cmdlist; 2737 c != NULL && c->name != NULL; c++) { 2738 if (binary->header.typecookie == c->cookie 2739 && binary->header.cmd == c->cmd) 2740 break; 2741 } 2742 if (c == NULL || c->name == NULL) { 2743 for (c = ng_generic_cmds; c->name != NULL; c++) { 2744 if (binary->header.typecookie == c->cookie 2745 && binary->header.cmd == c->cmd) 2746 break; 2747 } 2748 if (c->name == NULL) { 2749 NG_FREE_MSG(resp); 2750 error = ENOSYS; 2751 break; 2752 } 2753 } 2754 2755 /* Convert command name to ASCII */ 2756 snprintf(ascii->header.cmdstr, sizeof(ascii->header.cmdstr), 2757 "%s", c->name); 2758 2759 /* Convert command arguments to ASCII */ 2760 argstype = (binary->header.flags & NGF_RESP) ? 2761 c->respType : c->mesgType; 2762 if (argstype == NULL) { 2763 *ascii->data = '\0'; 2764 } else { 2765 if ((error = ng_unparse(argstype, 2766 (u_char *)binary->data, 2767 ascii->data, bufSize)) != 0) { 2768 NG_FREE_MSG(resp); 2769 break; 2770 } 2771 } 2772 2773 /* Return the result as struct ng_mesg plus ASCII string */ 2774 bufSize = strlen(ascii->data) + 1; 2775 ascii->header.arglen = bufSize; 2776 resp->header.arglen = sizeof(*ascii) + bufSize; 2777 break; 2778 } 2779 2780 case NGM_ASCII2BINARY: 2781 { 2782 int bufSize = 2000; /* XXX hard coded constant */ 2783 const struct ng_cmdlist *c; 2784 const struct ng_parse_type *argstype; 2785 struct ng_mesg *ascii, *binary; 2786 int off = 0; 2787 2788 /* Data area must contain at least a struct ng_mesg + '\0' */ 2789 ascii = (struct ng_mesg *)msg->data; 2790 if ((msg->header.arglen < sizeof(*ascii) + 1) 2791 || (ascii->header.arglen < 1) 2792 || (msg->header.arglen 2793 < sizeof(*ascii) + ascii->header.arglen)) { 2794 TRAP_ERROR(); 2795 error = EINVAL; 2796 break; 2797 } 2798 ascii->data[ascii->header.arglen - 1] = '\0'; 2799 2800 /* Get a response message with lots of room */ 2801 NG_MKRESPONSE(resp, msg, sizeof(*binary) + bufSize, M_NOWAIT); 2802 if (resp == NULL) { 2803 error = ENOMEM; 2804 break; 2805 } 2806 binary = (struct ng_mesg *)resp->data; 2807 2808 /* Copy ASCII message header to response message payload */ 2809 bcopy(ascii, binary, sizeof(*ascii)); 2810 2811 /* Find command by matching ASCII command string */ 2812 for (c = here->nd_type->cmdlist; 2813 c != NULL && c->name != NULL; c++) { 2814 if (strcmp(ascii->header.cmdstr, c->name) == 0) 2815 break; 2816 } 2817 if (c == NULL || c->name == NULL) { 2818 for (c = ng_generic_cmds; c->name != NULL; c++) { 2819 if (strcmp(ascii->header.cmdstr, c->name) == 0) 2820 break; 2821 } 2822 if (c->name == NULL) { 2823 NG_FREE_MSG(resp); 2824 error = ENOSYS; 2825 break; 2826 } 2827 } 2828 2829 /* Convert command name to binary */ 2830 binary->header.cmd = c->cmd; 2831 binary->header.typecookie = c->cookie; 2832 2833 /* Convert command arguments to binary */ 2834 argstype = (binary->header.flags & NGF_RESP) ? 2835 c->respType : c->mesgType; 2836 if (argstype == NULL) { 2837 bufSize = 0; 2838 } else { 2839 if ((error = ng_parse(argstype, ascii->data, 2840 &off, (u_char *)binary->data, &bufSize)) != 0) { 2841 NG_FREE_MSG(resp); 2842 break; 2843 } 2844 } 2845 2846 /* Return the result */ 2847 binary->header.arglen = bufSize; 2848 resp->header.arglen = sizeof(*binary) + bufSize; 2849 break; 2850 } 2851 2852 case NGM_TEXT_CONFIG: 2853 case NGM_TEXT_STATUS: 2854 /* 2855 * This one is tricky as it passes the command down to the 2856 * actual node, even though it is a generic type command. 2857 * This means we must assume that the item/msg is already freed 2858 * when control passes back to us. 2859 */ 2860 if (here->nd_type->rcvmsg != NULL) { 2861 NGI_MSG(item) = msg; /* put it back as we found it */ 2862 return((*here->nd_type->rcvmsg)(here, item, lasthook)); 2863 } 2864 /* Fall through if rcvmsg not supported */ 2865 default: 2866 TRAP_ERROR(); 2867 error = EINVAL; 2868 } 2869 /* 2870 * Sometimes a generic message may be statically allocated 2871 * to avoid problems with allocating when in tight memeory situations. 2872 * Don't free it if it is so. 2873 * I break them appart here, because erros may cause a free if the item 2874 * in which case we'd be doing it twice. 2875 * they are kept together above, to simplify freeing. 2876 */ 2877out: 2878 NG_RESPOND_MSG(error, here, item, resp); 2879 if (msg) 2880 NG_FREE_MSG(msg); 2881 return (error); 2882} 2883 2884/************************************************************************ 2885 Module routines 2886************************************************************************/ 2887 2888/* 2889 * Handle the loading/unloading of a netgraph node type module 2890 */ 2891int 2892ng_mod_event(module_t mod, int event, void *data) 2893{ 2894 struct ng_type *const type = data; 2895 int s, error = 0; 2896 2897 switch (event) { 2898 case MOD_LOAD: 2899 2900 /* Register new netgraph node type */ 2901 s = splnet(); 2902 if ((error = ng_newtype(type)) != 0) { 2903 splx(s); 2904 break; 2905 } 2906 2907 /* Call type specific code */ 2908 if (type->mod_event != NULL) 2909 if ((error = (*type->mod_event)(mod, event, data))) { 2910 mtx_lock(&ng_typelist_mtx); 2911 type->refs--; /* undo it */ 2912 LIST_REMOVE(type, types); 2913 mtx_unlock(&ng_typelist_mtx); 2914 } 2915 splx(s); 2916 break; 2917 2918 case MOD_UNLOAD: 2919 s = splnet(); 2920 if (type->refs > 1) { /* make sure no nodes exist! */ 2921 error = EBUSY; 2922 } else { 2923 if (type->refs == 0) { 2924 /* failed load, nothing to undo */ 2925 splx(s); 2926 break; 2927 } 2928 if (type->mod_event != NULL) { /* check with type */ 2929 error = (*type->mod_event)(mod, event, data); 2930 if (error != 0) { /* type refuses.. */ 2931 splx(s); 2932 break; 2933 } 2934 } 2935 mtx_lock(&ng_typelist_mtx); 2936 LIST_REMOVE(type, types); 2937 mtx_unlock(&ng_typelist_mtx); 2938 } 2939 splx(s); 2940 break; 2941 2942 default: 2943 if (type->mod_event != NULL) 2944 error = (*type->mod_event)(mod, event, data); 2945 else 2946 error = EOPNOTSUPP; /* XXX ? */ 2947 break; 2948 } 2949 return (error); 2950} 2951 2952/* 2953 * Handle loading and unloading for this code. 2954 * The only thing we need to link into is the NETISR strucure. 2955 */ 2956static int 2957ngb_mod_event(module_t mod, int event, void *data) 2958{ 2959 int s, error = 0; 2960 2961 switch (event) { 2962 case MOD_LOAD: 2963 /* Register line discipline */ 2964 mtx_init(&ng_worklist_mtx, "ng_worklist", NULL, MTX_SPIN); 2965 mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL, 2966 MTX_DEF); 2967 mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL, 2968 MTX_DEF); 2969 mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL, 2970 MTX_DEF); 2971 mtx_init(&ngq_mtx, "netgraph free item list mutex", NULL, 2972 MTX_DEF); 2973 s = splimp(); 2974 /* XXX could use NETISR_MPSAFE but need to verify code */ 2975 netisr_register(NETISR_NETGRAPH, (netisr_t *)ngintr, NULL, 0); 2976 splx(s); 2977 break; 2978 case MOD_UNLOAD: 2979 /* You cant unload it because an interface may be using it. */ 2980 error = EBUSY; 2981 break; 2982 default: 2983 error = EOPNOTSUPP; 2984 break; 2985 } 2986 return (error); 2987} 2988 2989static moduledata_t netgraph_mod = { 2990 "netgraph", 2991 ngb_mod_event, 2992 (NULL) 2993}; 2994DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_NETGRAPH, SI_ORDER_MIDDLE); 2995SYSCTL_NODE(_net, OID_AUTO, graph, CTLFLAG_RW, 0, "netgraph Family"); 2996SYSCTL_INT(_net_graph, OID_AUTO, abi_version, CTLFLAG_RD, 0, NG_ABI_VERSION,""); 2997SYSCTL_INT(_net_graph, OID_AUTO, msg_version, CTLFLAG_RD, 0, NG_VERSION, ""); 2998 2999/************************************************************************ 3000 Queue element get/free routines 3001************************************************************************/ 3002 3003 3004static int allocated; /* number of items malloc'd */ 3005 3006static int maxalloc = 128; /* limit the damage of a leak */ 3007static int ngqfreemax = 64;/* cache at most this many */ 3008 3009TUNABLE_INT("net.graph.maxalloc", &maxalloc); 3010SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 3011 0, "Maximum number of queue items to allocate"); 3012 3013TUNABLE_INT("net.graph.ngqfreemax", &ngqfreemax); 3014SYSCTL_INT(_net_graph, OID_AUTO, ngqfreemax, CTLFLAG_RDTUN, &ngqfreemax, 3015 0, "Maximum number of free queue items to cache"); 3016 3017static const int ngqfreelow = 4; /* try malloc if free < this */ 3018static volatile int ngqfreesize; /* number of cached entries */ 3019static volatile item_p ngqfree; /* free ones */ 3020 3021#ifdef NETGRAPH_DEBUG 3022static TAILQ_HEAD(, ng_item) ng_itemlist = TAILQ_HEAD_INITIALIZER(ng_itemlist); 3023#endif 3024/* 3025 * Get a queue entry 3026 * This is usually called when a packet first enters netgraph. 3027 * By definition, this is usually from an interrupt, or from a user. 3028 * Users are not so important, but try be quick for the times that it's 3029 * an interrupt. 3030 * XXX If reserve is low, we should try to get 2 from malloc as this 3031 * would indicate it often fails. 3032 */ 3033static item_p 3034ng_getqblk(void) 3035{ 3036 item_p item = NULL; 3037 3038 /* 3039 * Try get a cached queue block, or else allocate a new one 3040 * If we are less than our reserve, try malloc. If malloc 3041 * fails, then that's what the reserve is for... 3042 * We have our little reserve 3043 * because we use M_NOWAIT for malloc. This just helps us 3044 * avoid dropping packets while not increasing the time 3045 * we take to service the interrupt (on average) (I hope). 3046 */ 3047 mtx_lock(&ngq_mtx); 3048 3049 if ((ngqfreesize < ngqfreelow) || (ngqfree == NULL)) { 3050 if (allocated < maxalloc) { /* don't leak forever */ 3051 MALLOC(item, item_p , 3052 sizeof(*item), M_NETGRAPH_ITEM, 3053 (M_NOWAIT | M_ZERO)); 3054 if (item) { 3055#ifdef NETGRAPH_DEBUG 3056 TAILQ_INSERT_TAIL(&ng_itemlist, item, all); 3057#endif /* NETGRAPH_DEBUG */ 3058 allocated++; 3059 } 3060 } 3061 } 3062 3063 /* 3064 * We didn't or couldn't malloc. 3065 * try get one from our cache. 3066 */ 3067 if (item == NULL && (item = ngqfree) != NULL) { 3068 ngqfree = item->el_next; 3069 ngqfreesize--; 3070 item->el_flags &= ~NGQF_FREE; 3071 } 3072 3073 mtx_unlock(&ngq_mtx); 3074 return (item); 3075} 3076 3077/* 3078 * Release a queue entry 3079 */ 3080void 3081ng_free_item(item_p item) 3082{ 3083 3084 /* 3085 * The item may hold resources on it's own. We need to free 3086 * these before we can free the item. What they are depends upon 3087 * what kind of item it is. it is important that nodes zero 3088 * out pointers to resources that they remove from the item 3089 * or we release them again here. 3090 */ 3091 if (item->el_flags & NGQF_FREE) { 3092 panic(" Freeing free queue item"); 3093 } 3094 switch (item->el_flags & NGQF_TYPE) { 3095 case NGQF_DATA: 3096 /* If we have an mbuf still attached.. */ 3097 NG_FREE_M(_NGI_M(item)); 3098 break; 3099 case NGQF_MESG: 3100 _NGI_RETADDR(item) = 0; 3101 NG_FREE_MSG(_NGI_MSG(item)); 3102 break; 3103 case NGQF_FN: 3104 /* nothing to free really, */ 3105 _NGI_FN(item) = NULL; 3106 _NGI_ARG1(item) = NULL; 3107 _NGI_ARG2(item) = 0; 3108 case NGQF_UNDEF: 3109 break; 3110 } 3111 /* If we still have a node or hook referenced... */ 3112 _NGI_CLR_NODE(item); 3113 _NGI_CLR_HOOK(item); 3114 item->el_flags |= NGQF_FREE; 3115 3116 mtx_lock(&ngq_mtx); 3117 if (ngqfreesize < ngqfreemax) { 3118 ngqfreesize++; 3119 item->el_next = ngqfree; 3120 ngqfree = item; 3121 } else { 3122#ifdef NETGRAPH_DEBUG 3123 TAILQ_REMOVE(&ng_itemlist, item, all); 3124#endif /* NETGRAPH_DEBUG */ 3125 NG_FREE_ITEM_REAL(item); 3126 allocated--; 3127 } 3128 mtx_unlock(&ngq_mtx); 3129} 3130 3131#ifdef NETGRAPH_DEBUG 3132void 3133dumphook (hook_p hook, char *file, int line) 3134{ 3135 printf("hook: name %s, %d refs, Last touched:\n", 3136 _NG_HOOK_NAME(hook), hook->hk_refs); 3137 printf(" Last active @ %s, line %d\n", 3138 hook->lastfile, hook->lastline); 3139 if (line) { 3140 printf(" problem discovered at file %s, line %d\n", file, line); 3141 } 3142} 3143 3144void 3145dumpnode(node_p node, char *file, int line) 3146{ 3147 printf("node: ID [%x]: type '%s', %d hooks, flags 0x%x, %d refs, %s:\n", 3148 _NG_NODE_ID(node), node->nd_type->name, 3149 node->nd_numhooks, node->nd_flags, 3150 node->nd_refs, node->nd_name); 3151 printf(" Last active @ %s, line %d\n", 3152 node->lastfile, node->lastline); 3153 if (line) { 3154 printf(" problem discovered at file %s, line %d\n", file, line); 3155 } 3156} 3157 3158void 3159dumpitem(item_p item, char *file, int line) 3160{ 3161 if (item->el_flags & NGQF_FREE) { 3162 printf(" Free item, freed at %s, line %d\n", 3163 item->lastfile, item->lastline); 3164 } else { 3165 printf(" ACTIVE item, last used at %s, line %d", 3166 item->lastfile, item->lastline); 3167 switch(item->el_flags & NGQF_TYPE) { 3168 case NGQF_DATA: 3169 printf(" - [data]\n"); 3170 break; 3171 case NGQF_MESG: 3172 printf(" - retaddr[%d]:\n", _NGI_RETADDR(item)); 3173 break; 3174 case NGQF_FN: 3175 printf(" - fn@%p (%p, %p, %p, %d (%x))\n", 3176 item->body.fn.fn_fn, 3177 NGI_NODE(item), 3178 NGI_HOOK(item), 3179 item->body.fn.fn_arg1, 3180 item->body.fn.fn_arg2, 3181 item->body.fn.fn_arg2); 3182 break; 3183 case NGQF_UNDEF: 3184 printf(" - UNDEFINED!\n"); 3185 } 3186 } 3187 if (line) { 3188 printf(" problem discovered at file %s, line %d\n", file, line); 3189 if (NGI_NODE(item)) { 3190 printf("node %p ([%x])\n", 3191 NGI_NODE(item), ng_node2ID(NGI_NODE(item))); 3192 } 3193 } 3194} 3195 3196static void 3197ng_dumpitems(void) 3198{ 3199 item_p item; 3200 int i = 1; 3201 TAILQ_FOREACH(item, &ng_itemlist, all) { 3202 printf("[%d] ", i++); 3203 dumpitem(item, NULL, 0); 3204 } 3205} 3206 3207static void 3208ng_dumpnodes(void) 3209{ 3210 node_p node; 3211 int i = 1; 3212 mtx_lock(&ng_nodelist_mtx); 3213 SLIST_FOREACH(node, &ng_allnodes, nd_all) { 3214 printf("[%d] ", i++); 3215 dumpnode(node, NULL, 0); 3216 } 3217 mtx_unlock(&ng_nodelist_mtx); 3218} 3219 3220static void 3221ng_dumphooks(void) 3222{ 3223 hook_p hook; 3224 int i = 1; 3225 mtx_lock(&ng_nodelist_mtx); 3226 SLIST_FOREACH(hook, &ng_allhooks, hk_all) { 3227 printf("[%d] ", i++); 3228 dumphook(hook, NULL, 0); 3229 } 3230 mtx_unlock(&ng_nodelist_mtx); 3231} 3232 3233static int 3234sysctl_debug_ng_dump_items(SYSCTL_HANDLER_ARGS) 3235{ 3236 int error; 3237 int val; 3238 int i; 3239 3240 val = allocated; 3241 i = 1; 3242 error = sysctl_handle_int(oidp, &val, sizeof(int), req); 3243 if (error != 0 || req->newptr == NULL) 3244 return (error); 3245 if (val == 42) { 3246 ng_dumpitems(); 3247 ng_dumpnodes(); 3248 ng_dumphooks(); 3249 } 3250 return (0); 3251} 3252 3253SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, 3254 0, sizeof(int), sysctl_debug_ng_dump_items, "I", "Number of allocated items"); 3255#endif /* NETGRAPH_DEBUG */ 3256 3257 3258/*********************************************************************** 3259* Worklist routines 3260**********************************************************************/ 3261/* NETISR thread enters here */ 3262/* 3263 * Pick a node off the list of nodes with work, 3264 * try get an item to process off it. 3265 * If there are no more, remove the node from the list. 3266 */ 3267static void 3268ngintr(void) 3269{ 3270 item_p item; 3271 node_p node = NULL; 3272 3273 for (;;) { 3274 mtx_lock_spin(&ng_worklist_mtx); 3275 node = TAILQ_FIRST(&ng_worklist); 3276 if (!node) { 3277 mtx_unlock_spin(&ng_worklist_mtx); 3278 break; 3279 } 3280 node->nd_flags &= ~NGF_WORKQ; 3281 TAILQ_REMOVE(&ng_worklist, node, nd_work); 3282 mtx_unlock_spin(&ng_worklist_mtx); 3283 /* 3284 * We have the node. We also take over the reference 3285 * that the list had on it. 3286 * Now process as much as you can, until it won't 3287 * let you have another item off the queue. 3288 * All this time, keep the reference 3289 * that lets us be sure that the node still exists. 3290 * Let the reference go at the last minute. 3291 * ng_dequeue will put us back on the worklist 3292 * if there is more too do. This may be of use if there 3293 * are Multiple Processors and multiple Net threads in the 3294 * future. 3295 */ 3296 for (;;) { 3297 mtx_lock_spin(&node->nd_input_queue.q_mtx); 3298 item = ng_dequeue(&node->nd_input_queue); 3299 if (item == NULL) { 3300 mtx_unlock_spin(&node->nd_input_queue.q_mtx); 3301 break; /* go look for another node */ 3302 } else { 3303 mtx_unlock_spin(&node->nd_input_queue.q_mtx); 3304 NGI_GET_NODE(item, node); /* zaps stored node */ 3305 ng_apply_item(node, item); 3306 NG_NODE_UNREF(node); 3307 } 3308 } 3309 NG_NODE_UNREF(node); 3310 } 3311} 3312 3313static void 3314ng_worklist_remove(node_p node) 3315{ 3316 mtx_lock_spin(&ng_worklist_mtx); 3317 if (node->nd_flags & NGF_WORKQ) { 3318 node->nd_flags &= ~NGF_WORKQ; 3319 TAILQ_REMOVE(&ng_worklist, node, nd_work); 3320 mtx_unlock_spin(&ng_worklist_mtx); 3321 NG_NODE_UNREF(node); 3322 } else { 3323 mtx_unlock_spin(&ng_worklist_mtx); 3324 } 3325} 3326 3327/* 3328 * XXX 3329 * It's posible that a debugging NG_NODE_REF may need 3330 * to be outside the mutex zone 3331 */ 3332static void 3333ng_setisr(node_p node) 3334{ 3335 mtx_lock_spin(&ng_worklist_mtx); 3336 if ((node->nd_flags & NGF_WORKQ) == 0) { 3337 /* 3338 * If we are not already on the work queue, 3339 * then put us on. 3340 */ 3341 node->nd_flags |= NGF_WORKQ; 3342 TAILQ_INSERT_TAIL(&ng_worklist, node, nd_work); 3343 NG_NODE_REF(node); /* XXX fafe in mutex? */ 3344 } 3345 mtx_unlock_spin(&ng_worklist_mtx); 3346 schednetisr(NETISR_NETGRAPH); 3347} 3348 3349 3350/*********************************************************************** 3351* Externally useable functions to set up a queue item ready for sending 3352***********************************************************************/ 3353 3354#ifdef NETGRAPH_DEBUG 3355#define ITEM_DEBUG_CHECKS \ 3356 do { \ 3357 if (NGI_NODE(item) ) { \ 3358 printf("item already has node"); \ 3359 kdb_enter("has node"); \ 3360 NGI_CLR_NODE(item); \ 3361 } \ 3362 if (NGI_HOOK(item) ) { \ 3363 printf("item already has hook"); \ 3364 kdb_enter("has hook"); \ 3365 NGI_CLR_HOOK(item); \ 3366 } \ 3367 } while (0) 3368#else 3369#define ITEM_DEBUG_CHECKS 3370#endif 3371 3372/* 3373 * Put mbuf into the item. 3374 * Hook and node references will be removed when the item is dequeued. 3375 * (or equivalent) 3376 * (XXX) Unsafe because no reference held by peer on remote node. 3377 * remote node might go away in this timescale. 3378 * We know the hooks can't go away because that would require getting 3379 * a writer item on both nodes and we must have at least a reader 3380 * here to eb able to do this. 3381 * Note that the hook loaded is the REMOTE hook. 3382 * 3383 * This is possibly in the critical path for new data. 3384 */ 3385item_p 3386ng_package_data(struct mbuf *m, void *dummy) 3387{ 3388 item_p item; 3389 3390 if ((item = ng_getqblk()) == NULL) { 3391 NG_FREE_M(m); 3392 return (NULL); 3393 } 3394 ITEM_DEBUG_CHECKS; 3395 item->el_flags = NGQF_DATA; 3396 item->el_next = NULL; 3397 NGI_M(item) = m; 3398 return (item); 3399} 3400 3401/* 3402 * Allocate a queue item and put items into it.. 3403 * Evaluate the address as this will be needed to queue it and 3404 * to work out what some of the fields should be. 3405 * Hook and node references will be removed when the item is dequeued. 3406 * (or equivalent) 3407 */ 3408item_p 3409ng_package_msg(struct ng_mesg *msg) 3410{ 3411 item_p item; 3412 3413 if ((item = ng_getqblk()) == NULL) { 3414 NG_FREE_MSG(msg); 3415 return (NULL); 3416 } 3417 ITEM_DEBUG_CHECKS; 3418 item->el_flags = NGQF_MESG; 3419 item->el_next = NULL; 3420 /* 3421 * Set the current lasthook into the queue item 3422 */ 3423 NGI_MSG(item) = msg; 3424 NGI_RETADDR(item) = 0; 3425 return (item); 3426} 3427 3428 3429 3430#define SET_RETADDR(item, here, retaddr) \ 3431 do { /* Data or fn items don't have retaddrs */ \ 3432 if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) { \ 3433 if (retaddr) { \ 3434 NGI_RETADDR(item) = retaddr; \ 3435 } else { \ 3436 /* \ 3437 * The old return address should be ok. \ 3438 * If there isn't one, use the address \ 3439 * here. \ 3440 */ \ 3441 if (NGI_RETADDR(item) == 0) { \ 3442 NGI_RETADDR(item) \ 3443 = ng_node2ID(here); \ 3444 } \ 3445 } \ 3446 } \ 3447 } while (0) 3448 3449int 3450ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr) 3451{ 3452 hook_p peer; 3453 node_p peernode; 3454 ITEM_DEBUG_CHECKS; 3455 /* 3456 * Quick sanity check.. 3457 * Since a hook holds a reference on it's node, once we know 3458 * that the peer is still connected (even if invalid,) we know 3459 * that the peer node is present, though maybe invalid. 3460 */ 3461 if ((hook == NULL) 3462 || NG_HOOK_NOT_VALID(hook) 3463 || (NG_HOOK_PEER(hook) == NULL) 3464 || NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook)) 3465 || NG_NODE_NOT_VALID(NG_PEER_NODE(hook))) { 3466 NG_FREE_ITEM(item); 3467 TRAP_ERROR(); 3468 return (ENETDOWN); 3469 } 3470 3471 /* 3472 * Transfer our interest to the other (peer) end. 3473 */ 3474 peer = NG_HOOK_PEER(hook); 3475 NG_HOOK_REF(peer); 3476 NGI_SET_HOOK(item, peer); 3477 peernode = NG_PEER_NODE(hook); 3478 NG_NODE_REF(peernode); 3479 NGI_SET_NODE(item, peernode); 3480 SET_RETADDR(item, here, retaddr); 3481 return (0); 3482} 3483 3484int 3485ng_address_path(node_p here, item_p item, char *address, ng_ID_t retaddr) 3486{ 3487 node_p dest = NULL; 3488 hook_p hook = NULL; 3489 int error; 3490 3491 ITEM_DEBUG_CHECKS; 3492 /* 3493 * Note that ng_path2noderef increments the reference count 3494 * on the node for us if it finds one. So we don't have to. 3495 */ 3496 error = ng_path2noderef(here, address, &dest, &hook); 3497 if (error) { 3498 NG_FREE_ITEM(item); 3499 return (error); 3500 } 3501 NGI_SET_NODE(item, dest); 3502 if ( hook) { 3503 NG_HOOK_REF(hook); /* don't let it go while on the queue */ 3504 NGI_SET_HOOK(item, hook); 3505 } 3506 SET_RETADDR(item, here, retaddr); 3507 return (0); 3508} 3509 3510int 3511ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr) 3512{ 3513 node_p dest; 3514 3515 ITEM_DEBUG_CHECKS; 3516 /* 3517 * Find the target node. 3518 */ 3519 dest = ng_ID2noderef(ID); /* GETS REFERENCE! */ 3520 if (dest == NULL) { 3521 NG_FREE_ITEM(item); 3522 TRAP_ERROR(); 3523 return(EINVAL); 3524 } 3525 /* Fill out the contents */ 3526 item->el_flags = NGQF_MESG; 3527 item->el_next = NULL; 3528 NGI_SET_NODE(item, dest); 3529 NGI_CLR_HOOK(item); 3530 SET_RETADDR(item, here, retaddr); 3531 return (0); 3532} 3533 3534/* 3535 * special case to send a message to self (e.g. destroy node) 3536 * Possibly indicate an arrival hook too. 3537 * Useful for removing that hook :-) 3538 */ 3539item_p 3540ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg) 3541{ 3542 item_p item; 3543 3544 /* 3545 * Find the target node. 3546 * If there is a HOOK argument, then use that in preference 3547 * to the address. 3548 */ 3549 if ((item = ng_getqblk()) == NULL) { 3550 NG_FREE_MSG(msg); 3551 return (NULL); 3552 } 3553 3554 /* Fill out the contents */ 3555 item->el_flags = NGQF_MESG; 3556 item->el_next = NULL; 3557 NG_NODE_REF(here); 3558 NGI_SET_NODE(item, here); 3559 if (hook) { 3560 NG_HOOK_REF(hook); 3561 NGI_SET_HOOK(item, hook); 3562 } 3563 NGI_MSG(item) = msg; 3564 NGI_RETADDR(item) = ng_node2ID(here); 3565 return (item); 3566} 3567 3568int 3569ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, void * arg1, int arg2) 3570{ 3571 item_p item; 3572 3573 if ((item = ng_getqblk()) == NULL) { 3574 return (ENOMEM); 3575 } 3576 item->el_flags = NGQF_FN | NGQF_WRITER; 3577 NG_NODE_REF(node); /* and one for the item */ 3578 NGI_SET_NODE(item, node); 3579 if (hook) { 3580 NG_HOOK_REF(hook); 3581 NGI_SET_HOOK(item, hook); 3582 } 3583 NGI_FN(item) = fn; 3584 NGI_ARG1(item) = arg1; 3585 NGI_ARG2(item) = arg2; 3586 return(ng_snd_item(item, 0)); 3587} 3588 3589/* 3590 * Official timeout routines for Netgraph nodes. 3591 */ 3592static void 3593ng_callout_trapoline(void *arg) 3594{ 3595 item_p item = arg; 3596 3597 ng_snd_item(item, 0); 3598} 3599 3600 3601int 3602ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, 3603 ng_item_fn *fn, void * arg1, int arg2) 3604{ 3605 item_p item; 3606 3607 if ((item = ng_getqblk()) == NULL) 3608 return (ENOMEM); 3609 3610 item->el_flags = NGQF_FN | NGQF_WRITER; 3611 NG_NODE_REF(node); /* and one for the item */ 3612 NGI_SET_NODE(item, node); 3613 if (hook) { 3614 NG_HOOK_REF(hook); 3615 NGI_SET_HOOK(item, hook); 3616 } 3617 NGI_FN(item) = fn; 3618 NGI_ARG1(item) = arg1; 3619 NGI_ARG2(item) = arg2; 3620 callout_reset(c, ticks, &ng_callout_trapoline, item); 3621 return (0); 3622} 3623 3624/* A special modified version of untimeout() */ 3625int 3626ng_uncallout(struct callout *c, node_p node) 3627{ 3628 item_p item; 3629 int rval; 3630 void *c_func; 3631 3632 if (c == NULL) 3633 return (0); 3634 /* there must be an official way to do this */ 3635 mtx_lock_spin(&callout_lock); 3636 c_func = c->c_func; 3637 rval = callout_stop(c); 3638 mtx_unlock_spin(&callout_lock); 3639 item = c->c_arg; 3640 /* Do an extra check */ 3641 if ((rval > 0) && (c_func == &ng_callout_trapoline) && 3642 (NGI_NODE(item) == node)) { 3643 /* 3644 * We successfully removed it from the queue before it ran 3645 * So now we need to unreference everything that was 3646 * given extra references. (NG_FREE_ITEM does this). 3647 */ 3648 NG_FREE_ITEM(item); 3649 } 3650 3651 return (rval); 3652} 3653 3654/* 3655 * Set the address, if none given, give the node here. 3656 */ 3657void 3658ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr) 3659{ 3660 if (retaddr) { 3661 NGI_RETADDR(item) = retaddr; 3662 } else { 3663 /* 3664 * The old return address should be ok. 3665 * If there isn't one, use the address here. 3666 */ 3667 NGI_RETADDR(item) = ng_node2ID(here); 3668 } 3669} 3670 3671#define TESTING 3672#ifdef TESTING 3673/* just test all the macros */ 3674void 3675ng_macro_test(item_p item); 3676void 3677ng_macro_test(item_p item) 3678{ 3679 node_p node = NULL; 3680 hook_p hook = NULL; 3681 struct mbuf *m; 3682 struct ng_mesg *msg; 3683 ng_ID_t retaddr; 3684 int error; 3685 3686 NGI_GET_M(item, m); 3687 NGI_GET_MSG(item, msg); 3688 retaddr = NGI_RETADDR(item); 3689 NG_SEND_DATA(error, hook, m, NULL); 3690 NG_SEND_DATA_ONLY(error, hook, m); 3691 NG_FWD_NEW_DATA(error, item, hook, m); 3692 NG_FWD_ITEM_HOOK(error, item, hook); 3693 NG_SEND_MSG_HOOK(error, node, msg, hook, retaddr); 3694 NG_SEND_MSG_ID(error, node, msg, retaddr, retaddr); 3695 NG_SEND_MSG_PATH(error, node, msg, ".:", retaddr); 3696 NG_FWD_MSG_HOOK(error, node, item, hook, retaddr); 3697} 3698#endif /* TESTING */ 3699 3700