14cf49a43SJulian Elischer 24cf49a43SJulian Elischer /* 34cf49a43SJulian Elischer * ng_tee.c 4c398230bSWarner Losh */ 5c398230bSWarner Losh 6c398230bSWarner Losh /*- 74cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 84cf49a43SJulian Elischer * All rights reserved. 94cf49a43SJulian Elischer * 104cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 114cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 124cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 134cf49a43SJulian Elischer * provided, however, that: 144cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 154cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 164cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 174cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 184cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 194cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 204cf49a43SJulian Elischer * 214cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 224cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 234cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 244cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 254cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 264cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 274cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 284cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 294cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 304cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 314cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 324cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 334cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 344cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 354cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 364cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 374cf49a43SJulian Elischer * OF SUCH DAMAGE. 384cf49a43SJulian Elischer * 39cc3bbd68SJulian Elischer * Author: Julian Elischer <julian@freebsd.org> 404cf49a43SJulian Elischer * 414cf49a43SJulian Elischer * $FreeBSD$ 4274f5c6aaSJulian Elischer * $Whistle: ng_tee.c,v 1.18 1999/11/01 09:24:52 julian Exp $ 434cf49a43SJulian Elischer */ 444cf49a43SJulian Elischer 454cf49a43SJulian Elischer /* 464cf49a43SJulian Elischer * This node is like the tee(1) command and is useful for ``snooping.'' 474cf49a43SJulian Elischer * It has 4 hooks: left, right, left2right, and right2left. Data 484cf49a43SJulian Elischer * entering from the right is passed to the left and duplicated on 494cf49a43SJulian Elischer * right2left, and data entering from the left is passed to the right 504cf49a43SJulian Elischer * and duplicated on left2right. Data entering from left2right is 51722a139cSJulian Elischer * sent to left, and data from right2left to right. 524cf49a43SJulian Elischer */ 534cf49a43SJulian Elischer 544cf49a43SJulian Elischer #include <sys/param.h> 554cf49a43SJulian Elischer #include <sys/systm.h> 564cf49a43SJulian Elischer #include <sys/errno.h> 574cf49a43SJulian Elischer #include <sys/kernel.h> 584cf49a43SJulian Elischer #include <sys/malloc.h> 594cf49a43SJulian Elischer #include <sys/mbuf.h> 604cf49a43SJulian Elischer #include <netgraph/ng_message.h> 614cf49a43SJulian Elischer #include <netgraph/netgraph.h> 625c63f81fSArchie Cobbs #include <netgraph/ng_parse.h> 634cf49a43SJulian Elischer #include <netgraph/ng_tee.h> 644cf49a43SJulian Elischer 654cf49a43SJulian Elischer /* Per hook info */ 664cf49a43SJulian Elischer struct hookinfo { 674cf49a43SJulian Elischer hook_p hook; 68e632000eSAlexander Motin struct hookinfo *dest, *dup; 699cb887a6SArchie Cobbs struct ng_tee_hookstat stats; 704cf49a43SJulian Elischer }; 71e632000eSAlexander Motin typedef struct hookinfo *hi_p; 724cf49a43SJulian Elischer 734cf49a43SJulian Elischer /* Per node info */ 744cf49a43SJulian Elischer struct privdata { 754cf49a43SJulian Elischer struct hookinfo left; 764cf49a43SJulian Elischer struct hookinfo right; 774cf49a43SJulian Elischer struct hookinfo left2right; 784cf49a43SJulian Elischer struct hookinfo right2left; 794cf49a43SJulian Elischer }; 804cf49a43SJulian Elischer typedef struct privdata *sc_p; 814cf49a43SJulian Elischer 824cf49a43SJulian Elischer /* Netgraph methods */ 83e632000eSAlexander Motin static ng_constructor_t ng_tee_constructor; 84e632000eSAlexander Motin static ng_rcvmsg_t ng_tee_rcvmsg; 85e632000eSAlexander Motin static ng_close_t ng_tee_close; 86e632000eSAlexander Motin static ng_shutdown_t ng_tee_shutdown; 87e632000eSAlexander Motin static ng_newhook_t ng_tee_newhook; 88e632000eSAlexander Motin static ng_rcvdata_t ng_tee_rcvdata; 89e632000eSAlexander Motin static ng_disconnect_t ng_tee_disconnect; 904cf49a43SJulian Elischer 915c63f81fSArchie Cobbs /* Parse type for struct ng_tee_hookstat */ 92f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_tee_hookstat_type_fields[] 93f0184ff8SArchie Cobbs = NG_TEE_HOOKSTAT_INFO; 945c63f81fSArchie Cobbs static const struct ng_parse_type ng_tee_hookstat_type = { 955c63f81fSArchie Cobbs &ng_parse_struct_type, 96f0184ff8SArchie Cobbs &ng_tee_hookstat_type_fields 975c63f81fSArchie Cobbs }; 985c63f81fSArchie Cobbs 995c63f81fSArchie Cobbs /* Parse type for struct ng_tee_stats */ 100f0184ff8SArchie Cobbs static const struct ng_parse_struct_field ng_tee_stats_type_fields[] 101f0184ff8SArchie Cobbs = NG_TEE_STATS_INFO(&ng_tee_hookstat_type); 1025c63f81fSArchie Cobbs static const struct ng_parse_type ng_tee_stats_type = { 1035c63f81fSArchie Cobbs &ng_parse_struct_type, 104f0184ff8SArchie Cobbs &ng_tee_stats_type_fields 1055c63f81fSArchie Cobbs }; 1065c63f81fSArchie Cobbs 1075c63f81fSArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 1085c63f81fSArchie Cobbs static const struct ng_cmdlist ng_tee_cmds[] = { 1095c63f81fSArchie Cobbs { 1105c63f81fSArchie Cobbs NGM_TEE_COOKIE, 1115c63f81fSArchie Cobbs NGM_TEE_GET_STATS, 1125c63f81fSArchie Cobbs "getstats", 1135c63f81fSArchie Cobbs NULL, 1145c63f81fSArchie Cobbs &ng_tee_stats_type 1155c63f81fSArchie Cobbs }, 1165c63f81fSArchie Cobbs { 1175c63f81fSArchie Cobbs NGM_TEE_COOKIE, 1185c63f81fSArchie Cobbs NGM_TEE_CLR_STATS, 1195c63f81fSArchie Cobbs "clrstats", 1205c63f81fSArchie Cobbs NULL, 1215c63f81fSArchie Cobbs NULL 1225c63f81fSArchie Cobbs }, 12305215785SArchie Cobbs { 12405215785SArchie Cobbs NGM_TEE_COOKIE, 12505215785SArchie Cobbs NGM_TEE_GETCLR_STATS, 12605215785SArchie Cobbs "getclrstats", 12705215785SArchie Cobbs NULL, 12805215785SArchie Cobbs &ng_tee_stats_type 12905215785SArchie Cobbs }, 1305c63f81fSArchie Cobbs { 0 } 1315c63f81fSArchie Cobbs }; 1325c63f81fSArchie Cobbs 1334cf49a43SJulian Elischer /* Netgraph type descriptor */ 1345c63f81fSArchie Cobbs static struct ng_type ng_tee_typestruct = { 135f8aae777SJulian Elischer .version = NG_ABI_VERSION, 136f8aae777SJulian Elischer .name = NG_TEE_NODE_TYPE, 137e632000eSAlexander Motin .constructor = ng_tee_constructor, 138e632000eSAlexander Motin .rcvmsg = ng_tee_rcvmsg, 139e632000eSAlexander Motin .close = ng_tee_close, 140e632000eSAlexander Motin .shutdown = ng_tee_shutdown, 141e632000eSAlexander Motin .newhook = ng_tee_newhook, 142e632000eSAlexander Motin .rcvdata = ng_tee_rcvdata, 143e632000eSAlexander Motin .disconnect = ng_tee_disconnect, 144f8aae777SJulian Elischer .cmdlist = ng_tee_cmds, 1454cf49a43SJulian Elischer }; 1465c63f81fSArchie Cobbs NETGRAPH_INIT(tee, &ng_tee_typestruct); 1474cf49a43SJulian Elischer 1484cf49a43SJulian Elischer /* 1494cf49a43SJulian Elischer * Node constructor 1504cf49a43SJulian Elischer */ 1514cf49a43SJulian Elischer static int 152e632000eSAlexander Motin ng_tee_constructor(node_p node) 1534cf49a43SJulian Elischer { 1544cf49a43SJulian Elischer sc_p privdata; 1554cf49a43SJulian Elischer 15699cdf4ccSDavid Malone MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_NOWAIT|M_ZERO); 1574cf49a43SJulian Elischer if (privdata == NULL) 1584cf49a43SJulian Elischer return (ENOMEM); 1594cf49a43SJulian Elischer 16030400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, privdata); 1614cf49a43SJulian Elischer return (0); 1624cf49a43SJulian Elischer } 1634cf49a43SJulian Elischer 1644cf49a43SJulian Elischer /* 1654cf49a43SJulian Elischer * Add a hook 1664cf49a43SJulian Elischer */ 1674cf49a43SJulian Elischer static int 168e632000eSAlexander Motin ng_tee_newhook(node_p node, hook_p hook, const char *name) 1694cf49a43SJulian Elischer { 170e632000eSAlexander Motin sc_p privdata = NG_NODE_PRIVATE(node); 171e632000eSAlexander Motin hi_p hinfo; 1724cf49a43SJulian Elischer 173e632000eSAlexander Motin /* Precalculate internal pathes. */ 1744cf49a43SJulian Elischer if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) { 175e632000eSAlexander Motin hinfo = &privdata->right; 176e632000eSAlexander Motin if (privdata->left.dest) 177e632000eSAlexander Motin privdata->left.dup = privdata->left.dest; 178e632000eSAlexander Motin privdata->left.dest = hinfo; 179e632000eSAlexander Motin privdata->right2left.dest = hinfo; 1804cf49a43SJulian Elischer } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) { 181e632000eSAlexander Motin hinfo = &privdata->left; 182e632000eSAlexander Motin if (privdata->right.dest) 183e632000eSAlexander Motin privdata->right.dup = privdata->right.dest; 184e632000eSAlexander Motin privdata->right.dest = hinfo; 185e632000eSAlexander Motin privdata->left2right.dest = hinfo; 1864cf49a43SJulian Elischer } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) { 187e632000eSAlexander Motin hinfo = &privdata->right2left; 188e632000eSAlexander Motin if (privdata->right.dest) 189e632000eSAlexander Motin privdata->right.dup = hinfo; 190e632000eSAlexander Motin else 191e632000eSAlexander Motin privdata->right.dest = hinfo; 1924cf49a43SJulian Elischer } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) { 193e632000eSAlexander Motin hinfo = &privdata->left2right; 194e632000eSAlexander Motin if (privdata->left.dest) 195e632000eSAlexander Motin privdata->left.dup = hinfo; 196e632000eSAlexander Motin else 197e632000eSAlexander Motin privdata->left.dest = hinfo; 1984cf49a43SJulian Elischer } else 1994cf49a43SJulian Elischer return (EINVAL); 200e632000eSAlexander Motin hinfo->hook = hook; 201e632000eSAlexander Motin bzero(&hinfo->stats, sizeof(hinfo->stats)); 202e632000eSAlexander Motin NG_HOOK_SET_PRIVATE(hook, hinfo); 2034cf49a43SJulian Elischer return (0); 2044cf49a43SJulian Elischer } 2054cf49a43SJulian Elischer 2064cf49a43SJulian Elischer /* 2079cb887a6SArchie Cobbs * Receive a control message 2084cf49a43SJulian Elischer */ 2094cf49a43SJulian Elischer static int 210e632000eSAlexander Motin ng_tee_rcvmsg(node_p node, item_p item, hook_p lasthook) 2114cf49a43SJulian Elischer { 21230400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node); 2139cb887a6SArchie Cobbs struct ng_mesg *resp = NULL; 2149cb887a6SArchie Cobbs int error = 0; 215069154d5SJulian Elischer struct ng_mesg *msg; 2169cb887a6SArchie Cobbs 217069154d5SJulian Elischer NGI_GET_MSG(item, msg); 2189cb887a6SArchie Cobbs switch (msg->header.typecookie) { 2199cb887a6SArchie Cobbs case NGM_TEE_COOKIE: 2209cb887a6SArchie Cobbs switch (msg->header.cmd) { 2219cb887a6SArchie Cobbs case NGM_TEE_GET_STATS: 22205215785SArchie Cobbs case NGM_TEE_CLR_STATS: 22305215785SArchie Cobbs case NGM_TEE_GETCLR_STATS: 2249cb887a6SArchie Cobbs { 2259cb887a6SArchie Cobbs struct ng_tee_stats *stats; 2269cb887a6SArchie Cobbs 22705215785SArchie Cobbs if (msg->header.cmd != NGM_TEE_CLR_STATS) { 2289cb887a6SArchie Cobbs NG_MKRESPONSE(resp, msg, 22905215785SArchie Cobbs sizeof(*stats), M_NOWAIT); 2309cb887a6SArchie Cobbs if (resp == NULL) { 2319cb887a6SArchie Cobbs error = ENOMEM; 2329cb887a6SArchie Cobbs goto done; 2339cb887a6SArchie Cobbs } 2349cb887a6SArchie Cobbs stats = (struct ng_tee_stats *)resp->data; 23505215785SArchie Cobbs bcopy(&sc->right.stats, &stats->right, 23605215785SArchie Cobbs sizeof(stats->right)); 23705215785SArchie Cobbs bcopy(&sc->left.stats, &stats->left, 23805215785SArchie Cobbs sizeof(stats->left)); 23905215785SArchie Cobbs bcopy(&sc->right2left.stats, &stats->right2left, 24005215785SArchie Cobbs sizeof(stats->right2left)); 24105215785SArchie Cobbs bcopy(&sc->left2right.stats, &stats->left2right, 24205215785SArchie Cobbs sizeof(stats->left2right)); 2439cb887a6SArchie Cobbs } 24405215785SArchie Cobbs if (msg->header.cmd != NGM_TEE_GET_STATS) { 24505215785SArchie Cobbs bzero(&sc->right.stats, 24605215785SArchie Cobbs sizeof(sc->right.stats)); 24705215785SArchie Cobbs bzero(&sc->left.stats, 24805215785SArchie Cobbs sizeof(sc->left.stats)); 2499cb887a6SArchie Cobbs bzero(&sc->right2left.stats, 2509cb887a6SArchie Cobbs sizeof(sc->right2left.stats)); 2519cb887a6SArchie Cobbs bzero(&sc->left2right.stats, 2529cb887a6SArchie Cobbs sizeof(sc->left2right.stats)); 25305215785SArchie Cobbs } 2549cb887a6SArchie Cobbs break; 25505215785SArchie Cobbs } 2569cb887a6SArchie Cobbs default: 2579cb887a6SArchie Cobbs error = EINVAL; 2589cb887a6SArchie Cobbs break; 2599cb887a6SArchie Cobbs } 2609cb887a6SArchie Cobbs break; 261069154d5SJulian Elischer case NGM_FLOW_COOKIE: 262e632000eSAlexander Motin if (lasthook == sc->left.hook || lasthook == sc->right.hook) { 263e632000eSAlexander Motin hi_p const hinfo = NG_HOOK_PRIVATE(lasthook); 264e632000eSAlexander Motin if (hinfo && hinfo->dest) { 265069154d5SJulian Elischer NGI_MSG(item) = msg; 266e632000eSAlexander Motin NG_FWD_ITEM_HOOK(error, item, hinfo->dest->hook); 267069154d5SJulian Elischer return (error); 268069154d5SJulian Elischer } 269069154d5SJulian Elischer } 270069154d5SJulian Elischer break; 2719cb887a6SArchie Cobbs default: 2729cb887a6SArchie Cobbs error = EINVAL; 2739cb887a6SArchie Cobbs break; 2749cb887a6SArchie Cobbs } 2759cb887a6SArchie Cobbs done: 276069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 277069154d5SJulian Elischer NG_FREE_MSG(msg); 2789cb887a6SArchie Cobbs return (error); 2794cf49a43SJulian Elischer } 2804cf49a43SJulian Elischer 2814cf49a43SJulian Elischer /* 2824cf49a43SJulian Elischer * Receive data on a hook 2834cf49a43SJulian Elischer * 2844cf49a43SJulian Elischer * If data comes in the right link send a copy out right2left, and then 2854cf49a43SJulian Elischer * send the original onwards out through the left link. 2864cf49a43SJulian Elischer * Do the opposite for data coming in from the left link. 2874cf49a43SJulian Elischer * Data coming in right2left or left2right is forwarded 2884cf49a43SJulian Elischer * on through the appropriate destination hook as if it had come 2894cf49a43SJulian Elischer * from the other side. 2904cf49a43SJulian Elischer */ 2914cf49a43SJulian Elischer static int 292e632000eSAlexander Motin ng_tee_rcvdata(hook_p hook, item_p item) 2934cf49a43SJulian Elischer { 294e632000eSAlexander Motin const hi_p hinfo = NG_HOOK_PRIVATE(hook); 295e632000eSAlexander Motin hi_p h; 2964cf49a43SJulian Elischer int error = 0; 297069154d5SJulian Elischer struct mbuf *m; 2984cf49a43SJulian Elischer 299069154d5SJulian Elischer m = NGI_M(item); 3004cf49a43SJulian Elischer 3019cb887a6SArchie Cobbs /* Update stats on incoming hook */ 3029cb887a6SArchie Cobbs hinfo->stats.inOctets += m->m_pkthdr.len; 3039cb887a6SArchie Cobbs hinfo->stats.inFrames++; 3044cf49a43SJulian Elischer 3053ca24c28SJulian Elischer /* Duplicate packet if requried */ 306e632000eSAlexander Motin if (hinfo->dup) { 3079cb887a6SArchie Cobbs struct mbuf *m2; 3089cb887a6SArchie Cobbs 309069154d5SJulian Elischer /* Copy packet (failure will not stop the original)*/ 310a163d034SWarner Losh m2 = m_dup(m, M_DONTWAIT); 311069154d5SJulian Elischer if (m2) { 3129cb887a6SArchie Cobbs /* Deliver duplicate */ 313e632000eSAlexander Motin h = hinfo->dup; 314e632000eSAlexander Motin NG_SEND_DATA_ONLY(error, h->hook, m2); 315f4b580b1SGleb Smirnoff if (error == 0) { 316e632000eSAlexander Motin h->stats.outOctets += m->m_pkthdr.len; 317e632000eSAlexander Motin h->stats.outFrames++; 318f4b580b1SGleb Smirnoff } 3199cb887a6SArchie Cobbs } 320069154d5SJulian Elischer } 3219cb887a6SArchie Cobbs /* Deliver frame out destination hook */ 322e632000eSAlexander Motin if (hinfo->dest) { 323e632000eSAlexander Motin h = hinfo->dest; 324e632000eSAlexander Motin h->stats.outOctets += m->m_pkthdr.len; 325e632000eSAlexander Motin h->stats.outFrames++; 326e632000eSAlexander Motin NG_FWD_ITEM_HOOK(error, item, h->hook); 3270598ef01SJulian Elischer } else 328069154d5SJulian Elischer NG_FREE_ITEM(item); 32953dc6459SJulian Elischer return (error); 3304cf49a43SJulian Elischer } 3314cf49a43SJulian Elischer 3324cf49a43SJulian Elischer /* 333991fc65aSJulian Elischer * We are going to be shut down soon 334991fc65aSJulian Elischer * 335991fc65aSJulian Elischer * If we have both a left and right hook, then we probably want to extricate 336991fc65aSJulian Elischer * ourselves and leave the two peers still linked to each other. Otherwise we 337991fc65aSJulian Elischer * should just shut down as a normal node would. 338991fc65aSJulian Elischer */ 339991fc65aSJulian Elischer static int 340e632000eSAlexander Motin ng_tee_close(node_p node) 341991fc65aSJulian Elischer { 342991fc65aSJulian Elischer const sc_p privdata = NG_NODE_PRIVATE(node); 343991fc65aSJulian Elischer 344991fc65aSJulian Elischer if (privdata->left.hook && privdata->right.hook) 345991fc65aSJulian Elischer ng_bypass(privdata->left.hook, privdata->right.hook); 346991fc65aSJulian Elischer 347991fc65aSJulian Elischer return (0); 348991fc65aSJulian Elischer } 349991fc65aSJulian Elischer 350991fc65aSJulian Elischer /* 3514cf49a43SJulian Elischer * Shutdown processing 3524cf49a43SJulian Elischer */ 3534cf49a43SJulian Elischer static int 354e632000eSAlexander Motin ng_tee_shutdown(node_p node) 3554cf49a43SJulian Elischer { 35630400f03SJulian Elischer const sc_p privdata = NG_NODE_PRIVATE(node); 3574cf49a43SJulian Elischer 35830400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 3594cf49a43SJulian Elischer FREE(privdata, M_NETGRAPH); 3604cf49a43SJulian Elischer return (0); 3614cf49a43SJulian Elischer } 3624cf49a43SJulian Elischer 3634cf49a43SJulian Elischer /* 3644cf49a43SJulian Elischer * Hook disconnection 3654cf49a43SJulian Elischer */ 3664cf49a43SJulian Elischer static int 367e632000eSAlexander Motin ng_tee_disconnect(hook_p hook) 3684cf49a43SJulian Elischer { 369e632000eSAlexander Motin sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 370e632000eSAlexander Motin hi_p const hinfo = NG_HOOK_PRIVATE(hook); 3714cf49a43SJulian Elischer 3726e551fb6SDavid E. O'Brien KASSERT(hinfo != NULL, ("%s: null info", __func__)); 3739cb887a6SArchie Cobbs hinfo->hook = NULL; 374e632000eSAlexander Motin 375e632000eSAlexander Motin /* Recalculate internal pathes. */ 376e632000eSAlexander Motin if (sc->left.dest == hinfo) { 377e632000eSAlexander Motin sc->left.dest = sc->left.dup; 378e632000eSAlexander Motin sc->left.dup = NULL; 379e632000eSAlexander Motin } else if (sc->left.dup == hinfo) 380e632000eSAlexander Motin sc->left.dup = NULL; 381e632000eSAlexander Motin if (sc->right.dest == hinfo) { 382e632000eSAlexander Motin sc->right.dest = sc->right.dup; 383e632000eSAlexander Motin sc->right.dup = NULL; 384e632000eSAlexander Motin } else if (sc->right.dup == hinfo) 385e632000eSAlexander Motin sc->right.dup = NULL; 386e632000eSAlexander Motin if (sc->left2right.dest == hinfo) 387e632000eSAlexander Motin sc->left2right.dest = NULL; 388e632000eSAlexander Motin if (sc->right2left.dest == hinfo) 389e632000eSAlexander Motin sc->right2left.dest = NULL; 390e632000eSAlexander Motin 391e632000eSAlexander Motin /* Die when last hook disconnected. */ 392e632000eSAlexander Motin if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) && 393e632000eSAlexander Motin NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 39430400f03SJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook)); 3954cf49a43SJulian Elischer return (0); 3964cf49a43SJulian Elischer } 397