1 /* 2 * netgraph.h 3 * 4 * Copyright (c) 1996-1999 Whistle Communications, Inc. 5 * All rights reserved. 6 * 7 * Subject to the following obligations and disclaimer of warranty, use and 8 * redistribution of this software, in source or object code forms, with or 9 * without modifications are expressly permitted by Whistle Communications; 10 * provided, however, that: 11 * 1. Any and all reproductions of the source or object code must include the 12 * copyright notice above and the following disclaimer of warranties; and 13 * 2. No rights are granted, in any manner or form, to use Whistle 14 * Communications, Inc. trademarks, including the mark "WHISTLE 15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16 * such appears in the above copyright notice or in the software. 17 * 18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34 * OF SUCH DAMAGE. 35 * 36 * Author: Julian Elischer <julian@freebsd.org> 37 * 38 * $FreeBSD$ 39 * $Whistle: netgraph.h,v 1.29 1999/11/01 07:56:13 julian Exp $ 40 */ 41 42 #ifndef _NETGRAPH_NETGRAPH_H_ 43 #define _NETGRAPH_NETGRAPH_H_ 1 44 45 #ifndef _KERNEL 46 #error "This file should not be included in user level programs" 47 #endif 48 49 #include <sys/queue.h> 50 #include <sys/malloc.h> 51 #include <sys/module.h> 52 #include <sys/mutex.h> 53 /* debugging options */ 54 #define NETGRAPH_DEBUG 55 #define NG_SEPARATE_MALLOC /* make modules use their own malloc types */ 56 57 /* 58 * This defines the in-kernel binary interface version. 59 * It is possible to change this but leave the external message 60 * API the same. Each type also has it's own cookies for versioning as well. 61 * Change it for NETGRAPH_DEBUG version so we cannot mix debug and non debug 62 * modules. 63 */ 64 #define _NG_ABI_VERSION 5 65 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 66 #define NG_ABI_VERSION (_NG_ABI_VERSION + 0x10000) 67 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 68 #define NG_ABI_VERSION _NG_ABI_VERSION 69 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 70 71 72 /* 73 * Forward references for the basic structures so we can 74 * define the typedefs and use them in the structures themselves. 75 */ 76 struct ng_hook ; 77 struct ng_node ; 78 struct ng_item ; 79 typedef struct ng_item *item_p; 80 typedef struct ng_node *node_p; 81 typedef struct ng_hook *hook_p; 82 83 /*********************************************************************** 84 ***************** Hook Structure and Methods ************************** 85 *********************************************************************** 86 * 87 * Structure of a hook 88 */ 89 struct ng_hook { 90 char hk_name[NG_HOOKLEN+1]; /* what this node knows this link as */ 91 void *hk_private; /* node dependant ID for this hook */ 92 int hk_flags; /* info about this hook/link */ 93 int hk_refs; /* dont actually free this till 0 */ 94 struct ng_hook *hk_peer; /* the other end of this link */ 95 struct ng_node *hk_node; /* The node this hook is attached to */ 96 LIST_ENTRY(ng_hook) hk_hooks; /* linked list of all hooks on node */ 97 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 98 #define HK_MAGIC 0x78573011 99 int hk_magic; 100 char *lastfile; 101 int lastline; 102 SLIST_ENTRY(ng_hook) hk_all; /* all existing items */ 103 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 104 }; 105 /* Flags for a hook */ 106 #define HK_INVALID 0x0001 /* don't trust it! */ 107 #define HK_QUEUE 0x0002 /* queue for later delivery */ 108 #define HK_FORCE_WRITER 0x0004 /* Incoming data queued as a writer */ 109 #define HK_DEAD 0x0008 /* This is the dead hook.. don't free */ 110 111 /* 112 * Public Methods for hook 113 * If you can't do it with these you probably shouldn;t be doing it. 114 */ 115 void ng_unref_hook(hook_p hook); /* don't move this */ 116 #define _NG_HOOK_REF(hook) atomic_add_int(&(hook)->hk_refs, 1) 117 #define _NG_HOOK_NAME(hook) ((hook)->hk_name) 118 #define _NG_HOOK_UNREF(hook) ng_unref_hook(hook) 119 #define _NG_HOOK_SET_PRIVATE(hook, val) do {(hook)->hk_private = val;} while (0) 120 #define _NG_HOOK_PRIVATE(hook) ((hook)->hk_private) 121 #define _NG_HOOK_NOT_VALID(hook) ((hook)->hk_flags & HK_INVALID) 122 #define _NG_HOOK_IS_VALID(hook) (!(hook)->hk_flags & HK_INVALID) 123 #define _NG_HOOK_NODE(hook) ((hook)->hk_node) /* only rvalue! */ 124 #define _NG_HOOK_PEER(hook) ((hook)->hk_peer) /* only rvalue! */ 125 #define _NG_HOOK_FORCE_WRITER(hook) \ 126 do { hook->hk_flags |= HK_FORCE_WRITER; } while (0) 127 #define _NG_HOOK_FORCE_QUEUE(hook) do { hook->hk_flags |= HK_QUEUE; } while (0) 128 129 /* Some shortcuts */ 130 #define NG_PEER_NODE(hook) NG_HOOK_NODE(NG_HOOK_PEER(hook)) 131 #define NG_PEER_HOOK_NAME(hook) NG_HOOK_NAME(NG_HOOK_PEER(hook)) 132 #define NG_PEER_NODE_NAME(hook) NG_NODE_NAME(NG_PEER_NODE(hook)) 133 134 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 135 #define _NN_ __FILE__,__LINE__ 136 void dumphook (hook_p hook, char *file, int line); 137 static __inline void _chkhook(hook_p hook, char *file, int line); 138 static __inline void _ng_hook_ref(hook_p hook, char * file, int line); 139 static __inline char * _ng_hook_name(hook_p hook, char * file, int line); 140 static __inline void _ng_hook_unref(hook_p hook, char * file, int line); 141 static __inline void _ng_hook_set_private(hook_p hook, 142 void * val, char * file, int line); 143 static __inline void * _ng_hook_private(hook_p hook, char * file, int line); 144 static __inline int _ng_hook_not_valid(hook_p hook, char * file, int line); 145 static __inline int _ng_hook_is_valid(hook_p hook, char * file, int line); 146 static __inline node_p _ng_hook_node(hook_p hook, char * file, int line); 147 static __inline hook_p _ng_hook_peer(hook_p hook, char * file, int line); 148 static __inline void _ng_hook_force_writer(hook_p hook, char * file, 149 int line); 150 static __inline void _ng_hook_force_queue(hook_p hook, char * file, int line); 151 152 static void __inline 153 _chkhook(hook_p hook, char *file, int line) 154 { 155 if (hook->hk_magic != HK_MAGIC) { 156 printf("Accessing freed hook "); 157 dumphook(hook, file, line); 158 } 159 hook->lastline = line; 160 hook->lastfile = file; 161 } 162 163 static __inline void 164 _ng_hook_ref(hook_p hook, char * file, int line) 165 { 166 _chkhook(hook, file, line); 167 _NG_HOOK_REF(hook); 168 } 169 170 static __inline char * 171 _ng_hook_name(hook_p hook, char * file, int line) 172 { 173 _chkhook(hook, file, line); 174 return (_NG_HOOK_NAME(hook)); 175 } 176 177 static __inline void 178 _ng_hook_unref(hook_p hook, char * file, int line) 179 { 180 _chkhook(hook, file, line); 181 _NG_HOOK_UNREF(hook); 182 } 183 184 static __inline void 185 _ng_hook_set_private(hook_p hook, void *val, char * file, int line) 186 { 187 _chkhook(hook, file, line); 188 _NG_HOOK_SET_PRIVATE(hook, val); 189 } 190 191 static __inline void * 192 _ng_hook_private(hook_p hook, char * file, int line) 193 { 194 _chkhook(hook, file, line); 195 return (_NG_HOOK_PRIVATE(hook)); 196 } 197 198 static __inline int 199 _ng_hook_not_valid(hook_p hook, char * file, int line) 200 { 201 _chkhook(hook, file, line); 202 return (_NG_HOOK_NOT_VALID(hook)); 203 } 204 205 static __inline int 206 _ng_hook_is_valid(hook_p hook, char * file, int line) 207 { 208 _chkhook(hook, file, line); 209 return (_NG_HOOK_IS_VALID(hook)); 210 } 211 212 static __inline node_p 213 _ng_hook_node(hook_p hook, char * file, int line) 214 { 215 _chkhook(hook, file, line); 216 return (_NG_HOOK_NODE(hook)); 217 } 218 219 static __inline hook_p 220 _ng_hook_peer(hook_p hook, char * file, int line) 221 { 222 _chkhook(hook, file, line); 223 return (_NG_HOOK_PEER(hook)); 224 } 225 226 static __inline void 227 _ng_hook_force_writer(hook_p hook, char * file, int line) 228 { 229 _chkhook(hook, file, line); 230 _NG_HOOK_FORCE_WRITER(hook); 231 } 232 233 static __inline void 234 _ng_hook_force_queue(hook_p hook, char * file, int line) 235 { 236 _chkhook(hook, file, line); 237 _NG_HOOK_FORCE_QUEUE(hook); 238 } 239 240 241 #define NG_HOOK_REF(hook) _ng_hook_ref(hook, _NN_) 242 #define NG_HOOK_NAME(hook) _ng_hook_name(hook, _NN_) 243 #define NG_HOOK_UNREF(hook) _ng_hook_unref(hook, _NN_) 244 #define NG_HOOK_SET_PRIVATE(hook, val) _ng_hook_set_private(hook, val, _NN_) 245 #define NG_HOOK_PRIVATE(hook) _ng_hook_private(hook, _NN_) 246 #define NG_HOOK_NOT_VALID(hook) _ng_hook_not_valid(hook, _NN_) 247 #define NG_HOOK_IS_VALID(hook) _ng_hook_is_valid(hook, _NN_) 248 #define NG_HOOK_NODE(hook) _ng_hook_node(hook, _NN_) 249 #define NG_HOOK_PEER(hook) _ng_hook_peer(hook, _NN_) 250 #define NG_HOOK_FORCE_WRITER(hook) _ng_hook_force_writer(hook, _NN_) 251 #define NG_HOOK_FORCE_QUEUE(hook) _ng_hook_force_queue(hook, _NN_) 252 253 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 254 255 #define NG_HOOK_REF(hook) _NG_HOOK_REF(hook) 256 #define NG_HOOK_NAME(hook) _NG_HOOK_NAME(hook) 257 #define NG_HOOK_UNREF(hook) _NG_HOOK_UNREF(hook) 258 #define NG_HOOK_SET_PRIVATE(hook, val) _NG_HOOK_SET_PRIVATE(hook, val) 259 #define NG_HOOK_PRIVATE(hook) _NG_HOOK_PRIVATE(hook) 260 #define NG_HOOK_NOT_VALID(hook) _NG_HOOK_NOT_VALID(hook) 261 #define NG_HOOK_IS_VALID(hook) _NG_HOOK_IS_VALID(hook) 262 #define NG_HOOK_NODE(hook) _NG_HOOK_NODE(hook) 263 #define NG_HOOK_PEER(hook) _NG_HOOK_PEER(hook) 264 #define NG_HOOK_FORCE_WRITER(hook) _NG_HOOK_FORCE_WRITER(hook) 265 #define NG_HOOK_FORCE_QUEUE(hook) _NG_HOOK_FORCE_QUEUE(hook) 266 267 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 268 269 /*********************************************************************** 270 ***************** Node Structure and Methods ************************** 271 *********************************************************************** 272 * Structure of a node 273 * including the eembedded queue structure. 274 * 275 * The structure for queueing Netgraph request items 276 * embedded in the node structure 277 */ 278 struct ng_queue { 279 u_long q_flags; 280 struct mtx q_mtx; 281 item_p queue; 282 item_p *last; 283 struct ng_node *q_node; /* find the front of the node.. */ 284 }; 285 286 struct ng_node { 287 char nd_name[NG_NODELEN+1]; /* optional globally unique name */ 288 struct ng_type *nd_type; /* the installed 'type' */ 289 int nd_flags; /* see below for bit definitions */ 290 int nd_refs; /* # of references to this node */ 291 int nd_numhooks; /* number of hooks */ 292 void *nd_private; /* node type dependant node ID */ 293 ng_ID_t nd_ID; /* Unique per node */ 294 LIST_HEAD(hooks, ng_hook) nd_hooks; /* linked list of node hooks */ 295 LIST_ENTRY(ng_node) nd_nodes; /* linked list of all nodes */ 296 LIST_ENTRY(ng_node) nd_idnodes; /* ID hash collision list */ 297 TAILQ_ENTRY(ng_node) nd_work; /* nodes with work to do */ 298 struct ng_queue nd_input_queue; /* input queue for locking */ 299 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 300 #define ND_MAGIC 0x59264837 301 int nd_magic; 302 char *lastfile; 303 int lastline; 304 SLIST_ENTRY(ng_node) nd_all; /* all existing nodes */ 305 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 306 }; 307 308 /* Flags for a node */ 309 #define NG_INVALID 0x00000001 /* free when refs go to 0 */ 310 #define NG_WORKQ 0x00000002 /* node is on the work queue */ 311 #define NG_FORCE_WRITER 0x00000004 /* Never multithread this node */ 312 #define NG_CLOSING 0x00000008 /* ng_rmnode() at work */ 313 #define NGF_TYPE1 0x10000000 /* reserved for type specific storage */ 314 #define NGF_TYPE2 0x20000000 /* reserved for type specific storage */ 315 #define NGF_TYPE3 0x40000000 /* reserved for type specific storage */ 316 #define NGF_TYPE4 0x80000000 /* reserved for type specific storage */ 317 318 /* 319 * Public methods for nodes. 320 * If you can't do it with these you probably shouldn't be doing it. 321 */ 322 void ng_unref_node(node_p node); /* don't move this */ 323 #define _NG_NODE_NAME(node) ((node)->nd_name + 0) 324 #define _NG_NODE_HAS_NAME(node) ((node)->nd_name[0] + 0) 325 #define _NG_NODE_ID(node) ((node)->nd_ID + 0) 326 #define _NG_NODE_REF(node) atomic_add_int(&(node)->nd_refs, 1) 327 #define _NG_NODE_UNREF(node) ng_unref_node(node) 328 #define _NG_NODE_SET_PRIVATE(node, val) do {(node)->nd_private = val;} while (0) 329 #define _NG_NODE_PRIVATE(node) ((node)->nd_private) 330 #define _NG_NODE_IS_VALID(node) (!((node)->nd_flags & NG_INVALID)) 331 #define _NG_NODE_NOT_VALID(node) ((node)->nd_flags & NG_INVALID) 332 #define _NG_NODE_NUMHOOKS(node) ((node)->nd_numhooks + 0) /* rvalue */ 333 #define _NG_NODE_FORCE_WRITER(node) \ 334 do{ node->nd_flags |= NG_FORCE_WRITER; }while (0) 335 /* 336 * The hook iterator. 337 * This macro will call a function of type ng_fn_eachhook for each 338 * hook attached to the node. If the function returns 0, then the 339 * iterator will stop and return a pointer to the hook that returned 0. 340 */ 341 typedef int ng_fn_eachhook(hook_p hook, void* arg); 342 #define _NG_NODE_FOREACH_HOOK(node, fn, arg, rethook) \ 343 do { \ 344 hook_p hook; \ 345 LIST_FOREACH(hook, &((node)->nd_hooks), hk_hooks) { \ 346 if ((fn)(hook, arg) == 0) { \ 347 (rethook) = hook; \ 348 break; \ 349 } \ 350 } \ 351 } while (0) 352 353 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 354 void dumpnode(node_p node, char *file, int line); 355 static void __inline _chknode(node_p node, char *file, int line); 356 static __inline char * _ng_node_name(node_p node, char *file, int line); 357 static __inline int _ng_node_has_name(node_p node, char *file, int line); 358 static __inline ng_ID_t _ng_node_id(node_p node, char *file, int line); 359 static __inline void _ng_node_ref(node_p node, char *file, int line); 360 static __inline void _ng_node_unref(node_p node, char *file, int line); 361 static __inline void _ng_node_set_private(node_p node, void * val, 362 char *file, int line); 363 static __inline void * _ng_node_private(node_p node, char *file, int line); 364 static __inline int _ng_node_is_valid(node_p node, char *file, int line); 365 static __inline int _ng_node_not_valid(node_p node, char *file, int line); 366 static __inline int _ng_node_numhooks(node_p node, char *file, int line); 367 static __inline void _ng_node_force_writer(node_p node, char *file, int line); 368 static __inline hook_p _ng_node_foreach_hook(node_p node, 369 ng_fn_eachhook *fn, void *arg, char *file, int line); 370 371 static void __inline 372 _chknode(node_p node, char *file, int line) 373 { 374 if (node->nd_magic != ND_MAGIC) { 375 printf("Accessing freed node "); 376 dumpnode(node, file, line); 377 } 378 node->lastline = line; 379 node->lastfile = file; 380 } 381 382 static __inline char * 383 _ng_node_name(node_p node, char *file, int line) 384 { 385 _chknode(node, file, line); 386 return(_NG_NODE_NAME(node)); 387 } 388 389 static __inline int 390 _ng_node_has_name(node_p node, char *file, int line) 391 { 392 _chknode(node, file, line); 393 return(_NG_NODE_HAS_NAME(node)); 394 } 395 396 static __inline ng_ID_t 397 _ng_node_id(node_p node, char *file, int line) 398 { 399 _chknode(node, file, line); 400 return(_NG_NODE_ID(node)); 401 } 402 403 static __inline void 404 _ng_node_ref(node_p node, char *file, int line) 405 { 406 _chknode(node, file, line); 407 _NG_NODE_REF(node); 408 } 409 410 static __inline void 411 _ng_node_unref(node_p node, char *file, int line) 412 { 413 _chknode(node, file, line); 414 _NG_NODE_UNREF(node); 415 } 416 417 static __inline void 418 _ng_node_set_private(node_p node, void * val, char *file, int line) 419 { 420 _chknode(node, file, line); 421 _NG_NODE_SET_PRIVATE(node, val); 422 } 423 424 static __inline void * 425 _ng_node_private(node_p node, char *file, int line) 426 { 427 _chknode(node, file, line); 428 return (_NG_NODE_PRIVATE(node)); 429 } 430 431 static __inline int 432 _ng_node_is_valid(node_p node, char *file, int line) 433 { 434 _chknode(node, file, line); 435 return(_NG_NODE_IS_VALID(node)); 436 } 437 438 static __inline int 439 _ng_node_not_valid(node_p node, char *file, int line) 440 { 441 _chknode(node, file, line); 442 return(_NG_NODE_NOT_VALID(node)); 443 } 444 445 static __inline int 446 _ng_node_numhooks(node_p node, char *file, int line) 447 { 448 _chknode(node, file, line); 449 return(_NG_NODE_NUMHOOKS(node)); 450 } 451 452 static __inline void 453 _ng_node_force_writer(node_p node, char *file, int line) 454 { 455 _chknode(node, file, line); 456 _NG_NODE_FORCE_WRITER(node); 457 } 458 459 static __inline hook_p 460 _ng_node_foreach_hook(node_p node, ng_fn_eachhook *fn, void *arg, 461 char *file, int line) 462 { 463 hook_p hook; 464 _chknode(node, file, line); 465 _NG_NODE_FOREACH_HOOK(node, fn, arg, hook); 466 return (hook); 467 } 468 469 #define NG_NODE_NAME(node) _ng_node_name(node, _NN_) 470 #define NG_NODE_HAS_NAME(node) _ng_node_has_name(node, _NN_) 471 #define NG_NODE_ID(node) _ng_node_id(node, _NN_) 472 #define NG_NODE_REF(node) _ng_node_ref(node, _NN_) 473 #define NG_NODE_UNREF(node) _ng_node_unref(node, _NN_) 474 #define NG_NODE_SET_PRIVATE(node, val) _ng_node_set_private(node, val, _NN_) 475 #define NG_NODE_PRIVATE(node) _ng_node_private(node, _NN_) 476 #define NG_NODE_IS_VALID(node) _ng_node_is_valid(node, _NN_) 477 #define NG_NODE_NOT_VALID(node) _ng_node_not_valid(node, _NN_) 478 #define NG_NODE_FORCE_WRITER(node) _ng_node_force_writer(node, _NN_) 479 #define NG_NODE_NUMHOOKS(node) _ng_node_numhooks(node, _NN_) 480 #define NG_NODE_FOREACH_HOOK(node, fn, arg, rethook) \ 481 do { \ 482 rethook = _ng_node_foreach_hook(node, fn, (void *)arg, _NN_); \ 483 } while (0) 484 485 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 486 487 #define NG_NODE_NAME(node) _NG_NODE_NAME(node) 488 #define NG_NODE_HAS_NAME(node) _NG_NODE_HAS_NAME(node) 489 #define NG_NODE_ID(node) _NG_NODE_ID(node) 490 #define NG_NODE_REF(node) _NG_NODE_REF(node) 491 #define NG_NODE_UNREF(node) _NG_NODE_UNREF(node) 492 #define NG_NODE_SET_PRIVATE(node, val) _NG_NODE_SET_PRIVATE(node, val) 493 #define NG_NODE_PRIVATE(node) _NG_NODE_PRIVATE(node) 494 #define NG_NODE_IS_VALID(node) _NG_NODE_IS_VALID(node) 495 #define NG_NODE_NOT_VALID(node) _NG_NODE_NOT_VALID(node) 496 #define NG_NODE_FORCE_WRITER(node) _NG_NODE_FORCE_WRITER(node) 497 #define NG_NODE_NUMHOOKS(node) _NG_NODE_NUMHOOKS(node) 498 #define NG_NODE_FOREACH_HOOK(node, fn, arg, rethook) \ 499 _NG_NODE_FOREACH_HOOK(node, fn, arg, rethook) 500 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 501 502 /*********************************************************************** 503 ***************** Meta Data Structures and Methods ******************** 504 *********************************************************************** 505 * 506 * The structure that holds meta_data about a data packet (e.g. priority) 507 * Nodes might add or subtract options as needed if there is room. 508 * They might reallocate the struct to make more room if they need to. 509 * Meta-data is still experimental. 510 */ 511 struct meta_field_header { 512 u_long cookie; /* cookie for the field. Skip fields you don't 513 * know about (same cookie as in messgaes) */ 514 u_short type; /* field ID */ 515 u_short len; /* total len of this field including extra 516 * data */ 517 char data[0]; /* data starts here */ 518 }; 519 520 /* To zero out an option 'in place' set it's cookie to this */ 521 #define NGM_INVALID_COOKIE 865455152 522 523 /* This part of the metadata is always present if the pointer is non NULL */ 524 struct ng_meta { 525 char priority; /* -ve is less priority, 0 is default */ 526 char discardability; /* higher is less valuable.. discard first */ 527 u_short allocated_len; /* amount malloc'd */ 528 u_short used_len; /* sum of all fields, options etc. */ 529 u_short flags; /* see below.. generic flags */ 530 struct meta_field_header options[0]; /* add as (if) needed */ 531 }; 532 typedef struct ng_meta *meta_p; 533 534 /* Flags for meta-data */ 535 #define NGMF_TEST 0x01 /* discard at the last moment before sending */ 536 #define NGMF_TRACE 0x02 /* trace when handing this data to a node */ 537 538 /*********************************************************************** 539 ************* Node Queue and Item Structures and Methods ************** 540 *********************************************************************** 541 * 542 */ 543 typedef int ng_item_fn(node_p node, hook_p hook, void *arg1, int arg2); 544 struct ng_item { 545 u_long el_flags; 546 item_p el_next; 547 node_p el_dest; /* The node it will be applied against (or NULL) */ 548 hook_p el_hook; /* Entering hook. Optional in Control messages */ 549 union { 550 struct { 551 struct mbuf *da_m; 552 meta_p da_meta; 553 } data; 554 struct { 555 struct ng_mesg *msg_msg; 556 ng_ID_t msg_retaddr; 557 } msg; 558 struct { 559 ng_item_fn *fn_fn; 560 void *fn_arg1; 561 int fn_arg2; 562 } fn; 563 } body; 564 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 565 char *lastfile; 566 int lastline; 567 TAILQ_ENTRY(ng_item) all; /* all existing items */ 568 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 569 }; 570 571 #define NGQF_TYPE 0x03 /* MASK of content definition */ 572 #define NGQF_MESG 0x00 /* the queue element is a message */ 573 #define NGQF_DATA 0x01 /* the queue element is data */ 574 #define NGQF_FN 0x02 /* the queue element is a function */ 575 #define NGQF_UNDEF 0x03 /* UNDEFINED */ 576 577 #define NGQF_RW 0x04 /* MASK for queue entry read/write */ 578 #define NGQF_READER 0x04 /* queued as a reader */ 579 #define NGQF_WRITER 0x00 /* queued as a writer */ 580 581 #define NGQF_FREE 0x08 582 583 /* 584 * Get the mbuf (etc) out of an item. 585 * Sets the value in the item to NULL in case we need to call NG_FREE_ITEM() 586 * with it, (to avoid freeing the things twice). 587 * If you don't want to zero out the item then realise that the 588 * item still owns it. 589 * Retaddr is different. There are no references on that. It's just a number. 590 * The debug versions must be either all used everywhere or not at all. 591 */ 592 593 #define _NGI_M(i) ((i)->body.data.da_m) 594 #define _NGI_META(i) ((i)->body.data.da_meta) 595 #define _NGI_MSG(i) ((i)->body.msg.msg_msg) 596 #define _NGI_RETADDR(i) ((i)->body.msg.msg_retaddr) 597 #define _NGI_FN(i) ((i)->body.fn.fn_fn) 598 #define _NGI_ARG1(i) ((i)->body.fn.fn_arg1) 599 #define _NGI_ARG2(i) ((i)->body.fn.fn_arg2) 600 601 #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ 602 void dumpitem(item_p item, char *file, int line); 603 static __inline void _ngi_check(item_p item, char *file, int line) ; 604 static __inline struct mbuf ** _ngi_m(item_p item, char *file, int line) ; 605 static __inline meta_p * _ngi_meta(item_p item, char *file, int line) ; 606 static __inline ng_ID_t * _ngi_retaddr(item_p item, char *file, 607 int line) ; 608 static __inline struct ng_mesg ** _ngi_msg(item_p item, char *file, 609 int line) ; 610 611 static __inline void 612 _ngi_check(item_p item, char *file, int line) 613 { 614 if (item->el_flags & NGQF_FREE) { 615 dumpitem(item, file, line); 616 panic ("free item!"); 617 } 618 (item)->lastline = line; 619 (item)->lastfile = file; 620 } 621 622 static __inline struct mbuf ** 623 _ngi_m(item_p item, char *file, int line) 624 { 625 _ngi_check(item, file, line); 626 return (&_NGI_M(item)); 627 } 628 629 static __inline meta_p * 630 _ngi_meta(item_p item, char *file, int line) 631 { 632 _ngi_check(item, file, line); 633 return (&_NGI_META(item)); 634 } 635 636 static __inline struct ng_mesg ** 637 _ngi_msg(item_p item, char *file, int line) 638 { 639 _ngi_check(item, file, line); 640 return (&_NGI_MSG(item)); 641 } 642 643 static __inline ng_ID_t * 644 _ngi_retaddr(item_p item, char *file, int line) 645 { 646 _ngi_check(item, file, line); 647 return (&_NGI_RETADDR(item)); 648 } 649 650 static __inline ng_item_fn ** 651 _ngi_fn(item_p item, char *file, int line) 652 { 653 _ngi_check(item, file, line); 654 return (&_NGI_FN(item)); 655 } 656 657 static __inline void ** 658 _ngi_arg1(item_p item, char *file, int line) 659 { 660 _ngi_check(item, file, line); 661 return (&_NGI_ARG1(item)); 662 } 663 664 static __inline int * 665 _ngi_arg2(item_p item, char *file, int line) 666 { 667 _ngi_check(item, file, line); 668 return (&_NGI_ARG2(item)); 669 } 670 671 #define NGI_M(i) (*_ngi_m(i, _NN_)) 672 #define NGI_META(i) (*_ngi_meta(i, _NN_)) 673 #define NGI_MSG(i) (*_ngi_msg(i, _NN_)) 674 #define NGI_RETADDR(i) (*_ngi_retaddr(i, _NN_)) 675 #define NGI_FN(i) (*_ngi_fn(i, _NN_)) 676 #define NGI_ARG1(i) (*_ngi_arg1(i, _NN_)) 677 #define NGI_ARG2(i) (*_ngi_arg2(i, _NN_)) 678 679 #define NGI_GET_M(i,m) \ 680 do { \ 681 m = NGI_M(i); \ 682 _NGI_M(i) = NULL; \ 683 } while (0) 684 685 #define NGI_GET_META(i,m) \ 686 do { \ 687 m = NGI_META(i); \ 688 _NGI_META(i) = NULL; \ 689 } while (0) 690 691 #define NGI_GET_MSG(i,m) \ 692 do { \ 693 m = NGI_MSG(i); \ 694 _NGI_MSG(i) = NULL; \ 695 } while (0) 696 697 #define NG_FREE_ITEM(item) \ 698 do { \ 699 _ngi_check(item, _NN_); \ 700 ng_free_item((item)); \ 701 } while (0) 702 703 #define SAVE_LINE(item) \ 704 do { \ 705 (item)->lastline = __LINE__; \ 706 (item)->lastfile = __FILE__; \ 707 } while (0) 708 709 #else /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 710 711 #define NGI_M(i) _NGI_M(i) 712 #define NGI_META(i) _NGI_META(i) 713 #define NGI_MSG(i) _NGI_MSG(i) 714 #define NGI_RETADDR(i) _NGI_RETADDR(i) 715 #define NGI_FN(i) _NGI_FN(i) 716 #define NGI_ARG1(i) _NGI_ARG1(i) 717 #define NGI_ARG2(i) _NGI_ARG2(i) 718 719 #define NGI_GET_M(i,m) do {m = NGI_M(i); NGI_M(i) = NULL; } while (0) 720 #define NGI_GET_META(i,m) do {m = NGI_META(i); NGI_META(i) = NULL;} while (0) 721 #define NGI_GET_MSG(i,m) do {m = NGI_MSG(i); NGI_MSG(i) = NULL; } while (0) 722 723 #define NG_FREE_ITEM(item) ng_free_item((item)) 724 #define SAVE_LINE(item) do {} while (0) 725 726 #endif /* NETGRAPH_DEBUG */ /*----------------------------------------------*/ 727 728 /********************************************************************** 729 * Data macros. Send, manipulate and free. 730 **********************************************************************/ 731 /* Send previously unpackeged data and metadata. */ 732 #define NG_SEND_DATA(error, hook, m, meta) \ 733 do { \ 734 item_p item; \ 735 if ((item = ng_package_data((m), (meta)))) { \ 736 if (!((error) = ng_address_hook(NULL, item, \ 737 hook, NULL))) { \ 738 SAVE_LINE(item); \ 739 (error) = ng_snd_item((item), 0); \ 740 } \ 741 } else { \ 742 (error) = ENOMEM; \ 743 } \ 744 (m) = NULL; \ 745 (meta) = NULL; \ 746 } while (0) 747 748 /* Send a previously unpackaged mbuf when we have no metadata to send */ 749 #define NG_SEND_DATA_ONLY(error, hook, m) \ 750 do { \ 751 item_p item; \ 752 if ((item = ng_package_data((m), NULL))) { \ 753 if (!((error) = ng_address_hook(NULL, item, \ 754 hook, NULL))) { \ 755 SAVE_LINE(item); \ 756 (error) = ng_snd_item((item), 0); \ 757 } \ 758 } else { \ 759 (error) = ENOMEM; \ 760 } \ 761 (m) = NULL; \ 762 } while (0) 763 764 /* 765 * Forward a data packet with no new meta-data. 766 * old metadata is passed along without change. 767 * Mbuf pointer is updated to new value. We presume you dealt with the 768 * old one when you update it to the new one (or it maybe the old one). 769 * We got a packet and possibly had to modify the mbuf. 770 * You should probably use NGI_GET_M() if you are going to use this too 771 */ 772 #define NG_FWD_NEW_DATA(error, item, hook, m) \ 773 do { \ 774 NGI_M(item) = m; \ 775 if (!((error) = ng_address_hook(NULL, (item), \ 776 (hook), NULL))) { \ 777 SAVE_LINE(item); \ 778 (error) = ng_snd_item((item), 0); \ 779 } \ 780 (item) = NULL; \ 781 (m) = NULL; \ 782 } while (0) 783 784 /* 785 * Assuming the data is already ok, just set the new address and send 786 */ 787 #define NG_FWD_ITEM_HOOK(error, item, hook) \ 788 do { \ 789 if (!((error) = ng_address_hook(NULL, (item), \ 790 (hook), NULL))) { \ 791 SAVE_LINE(item); \ 792 (error) = ng_snd_item((item), 0); \ 793 } else { \ 794 (error) = ENXIO; \ 795 } \ 796 (item) = NULL; \ 797 } while (0) 798 799 800 /* Note that messages can be static (e.g. in ng_rmnode_self()) */ 801 /* XXX flag should not be user visible */ 802 #define NG_FREE_MSG(msg) \ 803 do { \ 804 if ((msg)) { \ 805 if ((msg->header.flags & NGF_STATIC) == 0) { \ 806 FREE((msg), M_NETGRAPH_MSG); \ 807 } \ 808 (msg) = NULL; \ 809 } \ 810 } while (0) 811 812 #define NG_FREE_META(meta) \ 813 do { \ 814 if ((meta)) { \ 815 FREE((meta), M_NETGRAPH_META); \ 816 (meta) = NULL; \ 817 } \ 818 } while (0) 819 820 #define NG_FREE_M(m) \ 821 do { \ 822 if ((m)) { \ 823 m_freem((m)); \ 824 (m) = NULL; \ 825 } \ 826 } while (0) 827 828 /***************************************** 829 * Message macros 830 *****************************************/ 831 832 #define NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr) \ 833 do { \ 834 item_p item; \ 835 if ((item = ng_package_msg(msg)) == NULL) { \ 836 (msg) = NULL; \ 837 (error) = ENOMEM; \ 838 break; \ 839 } \ 840 if (((error) = ng_address_hook((here), (item), \ 841 (hook), (retaddr))) == 0) { \ 842 SAVE_LINE(item); \ 843 (error) = ng_snd_item((item), 0); \ 844 } \ 845 (msg) = NULL; \ 846 } while (0) 847 848 #define NG_SEND_MSG_PATH(error, here, msg, path, retaddr) \ 849 do { \ 850 item_p item; \ 851 if ((item = ng_package_msg(msg)) == NULL) { \ 852 (msg) = NULL; \ 853 (error) = ENOMEM; \ 854 break; \ 855 } \ 856 if (((error) = ng_address_path((here), (item), \ 857 (path), (retaddr))) == 0) { \ 858 SAVE_LINE(item); \ 859 (error) = ng_snd_item((item), 0); \ 860 } \ 861 (msg) = NULL; \ 862 } while (0) 863 864 #define NG_SEND_MSG_ID(error, here, msg, ID, retaddr) \ 865 do { \ 866 item_p item; \ 867 if ((item = ng_package_msg(msg)) == NULL) { \ 868 (msg) = NULL; \ 869 (error) = ENOMEM; \ 870 break; \ 871 } \ 872 if (((error) = ng_address_ID((here), (item), \ 873 (ID), (retaddr))) == 0) { \ 874 SAVE_LINE(item); \ 875 (error) = ng_snd_item((item), 0); \ 876 } \ 877 (msg) = NULL; \ 878 } while (0) 879 880 #define NG_QUEUE_MSG(error, here, msg, path, retaddr) \ 881 do { \ 882 item_p item; \ 883 if ((item = ng_package_msg(msg)) == NULL) { \ 884 (msg) = NULL; \ 885 (error) = ENOMEM; \ 886 break; \ 887 } \ 888 if (((error) = ng_address_path((here), (item), \ 889 (path), (retaddr))) == 0) { \ 890 SAVE_LINE(item); \ 891 (error) = ng_snd_item((item), 1); \ 892 } \ 893 (msg) = NULL; \ 894 } while (0) 895 896 /* 897 * Redirect the message to the next hop using the given hook. 898 * ng_retarget_msg() frees the item if there is an error 899 * and returns an error code. It returns 0 on success. 900 */ 901 #define NG_FWD_MSG_HOOK(error, here, item, hook, retaddr) \ 902 do { \ 903 if (((error) = ng_address_hook((here), (item), \ 904 (hook), (retaddr))) == 0) { \ 905 SAVE_LINE(item); \ 906 (error) = ng_snd_item((item), 0); \ 907 } \ 908 (item) = NULL; \ 909 } while (0) 910 911 /* 912 * Send a queue item back to it's originator with a response message. 913 * Assume original message was removed and freed separatly. 914 */ 915 #define NG_RESPOND_MSG(error, here, item, resp) \ 916 do { \ 917 if (resp) { \ 918 ng_ID_t dest = NGI_RETADDR(item); \ 919 NGI_RETADDR(item) = NULL; \ 920 NGI_MSG(item) = resp; \ 921 if ((ng_address_ID((here), (item), \ 922 dest, NULL )) == 0) { \ 923 SAVE_LINE(item); \ 924 (error) = ng_snd_item((item), 1); \ 925 } else { \ 926 (error) = EINVAL; \ 927 } \ 928 } else { \ 929 NG_FREE_ITEM(item); \ 930 } \ 931 (item) = NULL; \ 932 } while (0) 933 934 935 /*********************************************************************** 936 ******** Structures Definitions and Macros for defining a node ******* 937 *********************************************************************** 938 * 939 * Here we define the structures needed to actually define a new node 940 * type. 941 */ 942 943 /* node method definitions */ 944 typedef int ng_constructor_t(node_p node); 945 typedef int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook); 946 typedef int ng_shutdown_t(node_p node); 947 typedef int ng_newhook_t(node_p node, hook_p hook, const char *name); 948 typedef hook_p ng_findhook_t(node_p node, const char *name); 949 typedef int ng_connect_t(hook_p hook); 950 typedef int ng_rcvdata_t(hook_p hook, item_p item); 951 typedef int ng_disconnect_t(hook_p hook); 952 typedef int ng_rcvitem (node_p node, hook_p hook, item_p item); 953 /* 954 * Command list -- each node type specifies the command that it knows 955 * how to convert between ASCII and binary using an array of these. 956 * The last element in the array must be a terminator with cookie=0. 957 */ 958 959 struct ng_cmdlist { 960 u_int32_t cookie; /* command typecookie */ 961 int cmd; /* command number */ 962 const char *name; /* command name */ 963 const struct ng_parse_type *mesgType; /* args if !NGF_RESP */ 964 const struct ng_parse_type *respType; /* args if NGF_RESP */ 965 }; 966 967 /* 968 * Structure of a node type 969 * If data is sent to the "rcvdata()" entrypoint then the system 970 * may decide to defer it until later by queing it with the normal netgraph 971 * input queuing system. This is decidde by the HK_QUEUE flag being set in 972 * the flags word of the peer (receiving) hook. The dequeuing mechanism will 973 * ensure it is not requeued again. 974 * Note the input queueing system is to allow modules 975 * to 'release the stack' or to pass data across spl layers. 976 * The data will be redelivered as soon as the NETISR code runs 977 * which may be almost immediatly. A node may also do it's own queueing 978 * for other reasons (e.g. device output queuing). 979 */ 980 struct ng_type { 981 982 u_int32_t version; /* must equal NG_API_VERSION */ 983 const char *name; /* Unique type name */ 984 modeventhand_t mod_event; /* Module event handler (optional) */ 985 ng_constructor_t *constructor; /* Node constructor */ 986 ng_rcvmsg_t *rcvmsg; /* control messages come here */ 987 ng_shutdown_t *shutdown; /* reset, and free resources */ 988 ng_newhook_t *newhook; /* first notification of new hook */ 989 ng_findhook_t *findhook; /* only if you have lots of hooks */ 990 ng_connect_t *connect; /* final notification of new hook */ 991 ng_rcvdata_t *rcvdata; /* data comes here */ 992 ng_disconnect_t *disconnect; /* notify on disconnect */ 993 994 const struct ng_cmdlist *cmdlist; /* commands we can convert */ 995 996 /* R/W data private to the base netgraph code DON'T TOUCH! */ 997 LIST_ENTRY(ng_type) types; /* linked list of all types */ 998 int refs; /* number of instances */ 999 }; 1000 1001 /* 1002 * Use the NETGRAPH_INIT() macro to link a node type into the 1003 * netgraph system. This works for types compiled into the kernel 1004 * as well as KLD modules. The first argument should be the type 1005 * name (eg, echo) and the second a pointer to the type struct. 1006 * 1007 * If a different link time is desired, e.g., a device driver that 1008 * needs to install its netgraph type before probing, use the 1009 * NETGRAPH_INIT_ORDERED() macro instead. Deivce drivers probably 1010 * want to use SI_SUB_DRIVERS instead of SI_SUB_PSEUDO. 1011 */ 1012 1013 #define NETGRAPH_INIT_ORDERED(typename, typestructp, sub, order) \ 1014 static moduledata_t ng_##typename##_mod = { \ 1015 "ng_" #typename, \ 1016 ng_mod_event, \ 1017 (typestructp) \ 1018 }; \ 1019 DECLARE_MODULE(ng_##typename, ng_##typename##_mod, sub, order); \ 1020 MODULE_DEPEND(ng_##typename, netgraph, 1, 1, 1) 1021 1022 #define NETGRAPH_INIT(tn, tp) \ 1023 NETGRAPH_INIT_ORDERED(tn, tp, SI_SUB_PSEUDO, SI_ORDER_ANY) 1024 1025 /* Special malloc() type for netgraph structs and ctrl messages */ 1026 /* Only these two types should be visible to nodes */ 1027 MALLOC_DECLARE(M_NETGRAPH); 1028 MALLOC_DECLARE(M_NETGRAPH_MSG); 1029 MALLOC_DECLARE(M_NETGRAPH_META); 1030 1031 1032 1033 /* 1034 * Methods that the nodes can use. 1035 * Many of these methods should usually NOT be used directly but via 1036 * Macros above. 1037 */ 1038 int ng_address_ID(node_p here, item_p item, ng_ID_t ID, ng_ID_t retaddr); 1039 int ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr); 1040 int ng_address_path(node_p here, item_p item, char *address, ng_ID_t raddr); 1041 meta_p ng_copy_meta(meta_p meta); 1042 hook_p ng_findhook(node_p node, const char *name); 1043 int ng_make_node_common(struct ng_type *typep, node_p *nodep); 1044 int ng_name_node(node_p node, const char *name); 1045 int ng_newtype(struct ng_type *tp); 1046 ng_ID_t ng_node2ID(node_p node); 1047 item_p ng_package_data(struct mbuf *m, meta_p meta); 1048 item_p ng_package_msg(struct ng_mesg *msg); 1049 item_p ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg); 1050 void ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr); 1051 int ng_rmhook_self(hook_p hook); /* if a node wants to kill a hook */ 1052 int ng_rmnode_self(node_p here); /* if a node wants to suicide */ 1053 int ng_snd_item(item_p item, int queue); 1054 int ng_send_fn(node_p node, hook_p hook, ng_item_fn *fn, 1055 void *arg1, int arg2); 1056 1057 /* 1058 * prototypes the user should DEFINITLY not use directly 1059 */ 1060 void ng_free_item(item_p item); /* Use NG_FREE_ITEM instead */ 1061 int ng_mod_event(module_t mod, int what, void *arg); 1062 1063 #endif /* _NETGRAPH_NETGRAPH_H_ */ 1064 1065