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