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