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