1208946Sae/*- 2208946Sae * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com> 3208946Sae * All rights reserved. 4208946Sae * 5208946Sae * Redistribution and use in source and binary forms, with or without 6208946Sae * modification, are permitted provided that the following conditions 7208946Sae * are met: 8208946Sae * 1. Redistributions of source code must retain the above copyright 9208946Sae * notice, this list of conditions and the following disclaimer. 10208946Sae * 2. Redistributions in binary form must reproduce the above copyright 11208946Sae * notice, this list of conditions and the following disclaimer in the 12208946Sae * documentation and/or other materials provided with the distribution. 13208946Sae * 14208946Sae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15208946Sae * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16208946Sae * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17208946Sae * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18208946Sae * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19208946Sae * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20208946Sae * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21208946Sae * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22208946Sae * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23208946Sae * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24208946Sae * SUCH DAMAGE. 25208946Sae * 26208946Sae */ 27208946Sae 28208946Sae#include <sys/cdefs.h> 29208946Sae__FBSDID("$FreeBSD$"); 30208946Sae 31208946Sae#include <sys/param.h> 32209194Sae#include <sys/systm.h> 33208946Sae#include <sys/kernel.h> 34209194Sae#include <sys/endian.h> 35208989Sae#include <sys/malloc.h> 36208989Sae#include <sys/mbuf.h> 37208946Sae#include <netgraph/ng_message.h> 38208946Sae#include <netgraph/ng_parse.h> 39208946Sae#include <netgraph/ng_patch.h> 40208946Sae#include <netgraph/netgraph.h> 41208946Sae 42208946Saestatic ng_constructor_t ng_patch_constructor; 43208946Saestatic ng_rcvmsg_t ng_patch_rcvmsg; 44208946Saestatic ng_shutdown_t ng_patch_shutdown; 45208946Saestatic ng_newhook_t ng_patch_newhook; 46208946Saestatic ng_rcvdata_t ng_patch_rcvdata; 47208946Saestatic ng_disconnect_t ng_patch_disconnect; 48208946Sae 49208946Saestatic int 50208989Saeng_patch_config_getlen(const struct ng_parse_type *type, 51208989Sae const u_char *start, const u_char *buf) 52208946Sae{ 53208946Sae const struct ng_patch_config *p; 54208946Sae 55208946Sae p = (const struct ng_patch_config *)(buf - 56209194Sae offsetof(struct ng_patch_config, ops)); 57208946Sae return (p->count); 58208946Sae} 59208946Sae 60208946Saestatic const struct ng_parse_struct_field ng_patch_op_type_fields[] 61208946Sae = NG_PATCH_OP_TYPE_INFO; 62208946Saestatic const struct ng_parse_type ng_patch_op_type = { 63208946Sae &ng_parse_struct_type, 64208946Sae &ng_patch_op_type_fields 65208946Sae}; 66208946Sae 67208946Saestatic const struct ng_parse_array_info ng_patch_confarr_info = { 68208946Sae &ng_patch_op_type, 69208946Sae &ng_patch_config_getlen 70208946Sae}; 71208946Saestatic const struct ng_parse_type ng_patch_confarr_type = { 72208946Sae &ng_parse_array_type, 73208946Sae &ng_patch_confarr_info 74208946Sae}; 75208946Sae 76208946Saestatic const struct ng_parse_struct_field ng_patch_config_type_fields[] 77208946Sae = NG_PATCH_CONFIG_TYPE_INFO; 78208946Saestatic const struct ng_parse_type ng_patch_config_type = { 79208946Sae &ng_parse_struct_type, 80208946Sae &ng_patch_config_type_fields 81208946Sae}; 82208946Sae 83208946Saestatic const struct ng_parse_struct_field ng_patch_stats_fields[] 84208946Sae = NG_PATCH_STATS_TYPE_INFO; 85208946Saestatic const struct ng_parse_type ng_patch_stats_type = { 86208946Sae &ng_parse_struct_type, 87208946Sae &ng_patch_stats_fields 88208946Sae}; 89208946Sae 90208946Saestatic const struct ng_cmdlist ng_patch_cmdlist[] = { 91208946Sae { 92208946Sae NGM_PATCH_COOKIE, 93208946Sae NGM_PATCH_GETCONFIG, 94208946Sae "getconfig", 95208946Sae NULL, 96208946Sae &ng_patch_config_type 97208946Sae }, 98208946Sae { 99208946Sae NGM_PATCH_COOKIE, 100208946Sae NGM_PATCH_SETCONFIG, 101208946Sae "setconfig", 102208946Sae &ng_patch_config_type, 103208946Sae NULL 104208946Sae }, 105208946Sae { 106208946Sae NGM_PATCH_COOKIE, 107208946Sae NGM_PATCH_GET_STATS, 108208946Sae "getstats", 109208946Sae NULL, 110208946Sae &ng_patch_stats_type 111208946Sae }, 112208946Sae { 113208946Sae NGM_PATCH_COOKIE, 114208946Sae NGM_PATCH_CLR_STATS, 115208946Sae "clrstats", 116208946Sae NULL, 117208946Sae NULL 118208946Sae }, 119208946Sae { 120208946Sae NGM_PATCH_COOKIE, 121208946Sae NGM_PATCH_GETCLR_STATS, 122208946Sae "getclrstats", 123208946Sae NULL, 124208946Sae &ng_patch_stats_type 125208946Sae }, 126208946Sae { 0 } 127208946Sae}; 128208946Sae 129208946Saestatic struct ng_type typestruct = { 130208946Sae .version = NG_ABI_VERSION, 131208946Sae .name = NG_PATCH_NODE_TYPE, 132208946Sae .constructor = ng_patch_constructor, 133208946Sae .rcvmsg = ng_patch_rcvmsg, 134208946Sae .shutdown = ng_patch_shutdown, 135208946Sae .newhook = ng_patch_newhook, 136208946Sae .rcvdata = ng_patch_rcvdata, 137208946Sae .disconnect = ng_patch_disconnect, 138208946Sae .cmdlist = ng_patch_cmdlist, 139208946Sae}; 140208946SaeNETGRAPH_INIT(patch, &typestruct); 141208946Sae 142208946Saeunion patch_val { 143208946Sae uint8_t v1; 144208946Sae uint16_t v2; 145208946Sae uint32_t v4; 146208946Sae uint64_t v8; 147208946Sae}; 148208946Sae 149208946Saestruct ng_patch_priv { 150208946Sae hook_p in; 151208946Sae hook_p out; 152208946Sae struct ng_patch_config *config; 153208946Sae union patch_val *val; 154208946Sae struct ng_patch_stats stats; 155208946Sae}; 156208946Saetypedef struct ng_patch_priv *priv_p; 157208946Sae 158208989Sae#define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \ 159208946Sae (count) * sizeof(struct ng_patch_op)) 160208946Sae 161208946Saestatic void do_patch(priv_p conf, struct mbuf *m); 162208946Sae 163208946Saestatic int 164208946Saeng_patch_constructor(node_p node) 165208946Sae{ 166208946Sae priv_p privdata; 167208946Sae 168220767Sae privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO); 169208946Sae NG_NODE_SET_PRIVATE(node, privdata); 170208946Sae privdata->in = NULL; 171208946Sae privdata->out = NULL; 172208946Sae privdata->config = NULL; 173208946Sae return (0); 174208946Sae} 175208946Sae 176208946Saestatic int 177208946Saeng_patch_newhook(node_p node, hook_p hook, const char *name) 178208946Sae{ 179208946Sae const priv_p privp = NG_NODE_PRIVATE(node); 180208946Sae 181208946Sae if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) { 182208946Sae privp->in = hook; 183208946Sae } else if (strncmp(name, NG_PATCH_HOOK_OUT, 184208946Sae strlen(NG_PATCH_HOOK_OUT)) == 0) { 185208946Sae privp->out = hook; 186208946Sae } else 187208946Sae return (EINVAL); 188208946Sae return(0); 189208946Sae} 190208946Sae 191208946Saestatic int 192208946Saeng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook) 193208946Sae{ 194208946Sae const priv_p privp = NG_NODE_PRIVATE(node); 195208989Sae struct ng_patch_config *conf, *newconf; 196208989Sae union patch_val *newval; 197208946Sae struct ng_mesg *msg; 198208989Sae struct ng_mesg *resp; 199208989Sae int i, clear, error; 200208946Sae 201208989Sae clear = error = 0; 202208989Sae resp = NULL; 203208946Sae NGI_GET_MSG(item, msg); 204208946Sae switch (msg->header.typecookie) { 205208946Sae case NGM_PATCH_COOKIE: 206208946Sae switch (msg->header.cmd) { 207208946Sae case NGM_PATCH_GETCONFIG: 208208946Sae if (privp->config == NULL) 209208946Sae break; 210208946Sae NG_MKRESPONSE(resp, msg, 211220767Sae NG_PATCH_CONF_SIZE(privp->config->count), 212220767Sae M_WAITOK); 213208946Sae bcopy(privp->config, resp->data, 214208946Sae NG_PATCH_CONF_SIZE(privp->config->count)); 215208946Sae break; 216208946Sae case NGM_PATCH_SETCONFIG: 217208946Sae { 218208989Sae if (msg->header.arglen < 219208989Sae sizeof(struct ng_patch_config)) { 220208946Sae error = EINVAL; 221208946Sae break; 222208946Sae } 223208946Sae 224208946Sae conf = (struct ng_patch_config *)msg->data; 225208989Sae if (msg->header.arglen < 226208989Sae NG_PATCH_CONF_SIZE(conf->count)) { 227208946Sae error = EINVAL; 228208946Sae break; 229208946Sae } 230208946Sae 231208946Sae for(i = 0; i < conf->count; i++) { 232208946Sae switch(conf->ops[i].length) { 233208946Sae case 1: 234208946Sae case 2: 235208946Sae case 4: 236208946Sae case 8: 237208946Sae break; 238208946Sae default: 239208946Sae error = EINVAL; 240208946Sae break; 241208946Sae } 242208946Sae if (error != 0) 243208946Sae break; 244208946Sae } 245208946Sae 246208946Sae conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP | 247208946Sae CSUM_SCTP; 248208946Sae 249208946Sae if (error == 0) { 250208989Sae newconf = malloc( 251208989Sae NG_PATCH_CONF_SIZE(conf->count), 252220767Sae M_NETGRAPH, M_WAITOK); 253208989Sae newval = malloc(conf->count * 254208989Sae sizeof(union patch_val), M_NETGRAPH, 255220767Sae M_WAITOK); 256208946Sae for(i = 0; i < conf->count; i++) { 257208946Sae switch (conf->ops[i].length) { 258208946Sae case 1: 259208989Sae newval[i].v1 = 260208989Sae conf->ops[i].value; 261208946Sae break; 262208946Sae case 2: 263208989Sae newval[i].v2 = 264208989Sae conf->ops[i].value; 265208946Sae break; 266208946Sae case 4: 267208989Sae newval[i].v4 = 268208989Sae conf->ops[i].value; 269208946Sae break; 270208946Sae case 8: 271208989Sae newval[i].v8 = 272208989Sae conf->ops[i].value; 273208946Sae break; 274208946Sae } 275208946Sae } 276208989Sae bcopy(conf, newconf, 277208989Sae NG_PATCH_CONF_SIZE(conf->count)); 278208946Sae if (privp->val != NULL) 279208946Sae free(privp->val, M_NETGRAPH); 280208946Sae privp->val = newval; 281208946Sae if (privp->config != NULL) 282208946Sae free(privp->config, M_NETGRAPH); 283208946Sae privp->config = newconf; 284208946Sae } 285208946Sae break; 286208946Sae } 287208946Sae case NGM_PATCH_GETCLR_STATS: 288208946Sae clear = 1; 289208946Sae /* FALLTHROUGH */ 290208946Sae case NGM_PATCH_GET_STATS: 291208946Sae NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), 292220767Sae M_WAITOK); 293208946Sae bcopy(&(privp->stats), resp->data, 294208946Sae sizeof(struct ng_patch_stats)); 295208946Sae if (clear == 0) 296208946Sae break; 297208946Sae /* else FALLTHROUGH */ 298208946Sae case NGM_PATCH_CLR_STATS: 299208946Sae bzero(&(privp->stats), sizeof(struct ng_patch_stats)); 300208946Sae break; 301208946Sae default: 302208946Sae error = EINVAL; 303208946Sae break; 304208946Sae } 305208946Sae break; 306208946Sae default: 307208946Sae error = EINVAL; 308208946Sae break; 309208946Sae } 310208946Sae 311208946Sae NG_RESPOND_MSG(error, node, item, resp); 312208946Sae NG_FREE_MSG(msg); 313208946Sae return(error); 314208946Sae} 315208946Sae 316208946Saestatic void 317208946Saedo_patch(priv_p privp, struct mbuf *m) 318208946Sae{ 319208989Sae struct ng_patch_config *conf; 320208946Sae uint64_t buf; 321208989Sae int i, patched; 322208946Sae 323208989Sae conf = privp->config; 324208989Sae patched = 0; 325208946Sae for(i = 0; i < conf->count; i++) { 326208989Sae if (conf->ops[i].offset + conf->ops[i].length > 327208989Sae m->m_pkthdr.len) 328208946Sae continue; 329208946Sae 330208946Sae /* for "=" operation we don't need to copy data from mbuf */ 331208946Sae if (conf->ops[i].mode != NG_PATCH_MODE_SET) { 332208946Sae m_copydata(m, conf->ops[i].offset, 333208946Sae conf->ops[i].length, (caddr_t)&buf); 334208946Sae } 335208989Sae 336208946Sae switch (conf->ops[i].length) { 337208946Sae case 1: 338208946Sae switch (conf->ops[i].mode) { 339208946Sae case NG_PATCH_MODE_SET: 340208946Sae *((uint8_t *)&buf) = privp->val[i].v1; 341208946Sae break; 342208946Sae case NG_PATCH_MODE_ADD: 343208946Sae *((uint8_t *)&buf) += privp->val[i].v1; 344208946Sae break; 345208946Sae case NG_PATCH_MODE_SUB: 346208946Sae *((uint8_t *)&buf) -= privp->val[i].v1; 347208946Sae break; 348208946Sae case NG_PATCH_MODE_MUL: 349208946Sae *((uint8_t *)&buf) *= privp->val[i].v1; 350208946Sae break; 351208946Sae case NG_PATCH_MODE_DIV: 352208946Sae *((uint8_t *)&buf) /= privp->val[i].v1; 353208946Sae break; 354208946Sae case NG_PATCH_MODE_NEG: 355208946Sae *((int8_t *)&buf) = - *((int8_t *)&buf); 356208946Sae break; 357208946Sae case NG_PATCH_MODE_AND: 358208946Sae *((uint8_t *)&buf) &= privp->val[i].v1; 359208946Sae break; 360208946Sae case NG_PATCH_MODE_OR: 361208946Sae *((uint8_t *)&buf) |= privp->val[i].v1; 362208946Sae break; 363208946Sae case NG_PATCH_MODE_XOR: 364208946Sae *((uint8_t *)&buf) ^= privp->val[i].v1; 365208946Sae break; 366208946Sae case NG_PATCH_MODE_SHL: 367208946Sae *((uint8_t *)&buf) <<= privp->val[i].v1; 368208946Sae break; 369208946Sae case NG_PATCH_MODE_SHR: 370208946Sae *((uint8_t *)&buf) >>= privp->val[i].v1; 371208946Sae break; 372208946Sae } 373208946Sae break; 374208946Sae case 2: 375208946Sae *((int16_t *)&buf) = ntohs(*((int16_t *)&buf)); 376208946Sae switch (conf->ops[i].mode) { 377208946Sae case NG_PATCH_MODE_SET: 378208946Sae *((uint16_t *)&buf) = privp->val[i].v2; 379208946Sae break; 380208946Sae case NG_PATCH_MODE_ADD: 381208946Sae *((uint16_t *)&buf) += privp->val[i].v2; 382208946Sae break; 383208946Sae case NG_PATCH_MODE_SUB: 384208946Sae *((uint16_t *)&buf) -= privp->val[i].v2; 385208946Sae break; 386208946Sae case NG_PATCH_MODE_MUL: 387208946Sae *((uint16_t *)&buf) *= privp->val[i].v2; 388208946Sae break; 389208946Sae case NG_PATCH_MODE_DIV: 390208946Sae *((uint16_t *)&buf) /= privp->val[i].v2; 391208946Sae break; 392208946Sae case NG_PATCH_MODE_NEG: 393208946Sae *((int16_t *)&buf) = - *((int16_t *)&buf); 394208946Sae break; 395208946Sae case NG_PATCH_MODE_AND: 396208946Sae *((uint16_t *)&buf) &= privp->val[i].v2; 397208946Sae break; 398208946Sae case NG_PATCH_MODE_OR: 399208946Sae *((uint16_t *)&buf) |= privp->val[i].v2; 400208946Sae break; 401208946Sae case NG_PATCH_MODE_XOR: 402208946Sae *((uint16_t *)&buf) ^= privp->val[i].v2; 403208946Sae break; 404208946Sae case NG_PATCH_MODE_SHL: 405208946Sae *((uint16_t *)&buf) <<= privp->val[i].v2; 406208946Sae break; 407208946Sae case NG_PATCH_MODE_SHR: 408208946Sae *((uint16_t *)&buf) >>= privp->val[i].v2; 409208946Sae break; 410208946Sae } 411208946Sae *((int16_t *)&buf) = htons(*((int16_t *)&buf)); 412208946Sae break; 413208946Sae case 4: 414208946Sae *((int32_t *)&buf) = ntohl(*((int32_t *)&buf)); 415208946Sae switch (conf->ops[i].mode) { 416208946Sae case NG_PATCH_MODE_SET: 417208946Sae *((uint32_t *)&buf) = privp->val[i].v4; 418208946Sae break; 419208946Sae case NG_PATCH_MODE_ADD: 420208946Sae *((uint32_t *)&buf) += privp->val[i].v4; 421208946Sae break; 422208946Sae case NG_PATCH_MODE_SUB: 423208946Sae *((uint32_t *)&buf) -= privp->val[i].v4; 424208946Sae break; 425208946Sae case NG_PATCH_MODE_MUL: 426208946Sae *((uint32_t *)&buf) *= privp->val[i].v4; 427208946Sae break; 428208946Sae case NG_PATCH_MODE_DIV: 429208946Sae *((uint32_t *)&buf) /= privp->val[i].v4; 430208946Sae break; 431208946Sae case NG_PATCH_MODE_NEG: 432208946Sae *((int32_t *)&buf) = - *((int32_t *)&buf); 433208946Sae break; 434208946Sae case NG_PATCH_MODE_AND: 435208946Sae *((uint32_t *)&buf) &= privp->val[i].v4; 436208946Sae break; 437208946Sae case NG_PATCH_MODE_OR: 438208946Sae *((uint32_t *)&buf) |= privp->val[i].v4; 439208946Sae break; 440208946Sae case NG_PATCH_MODE_XOR: 441208946Sae *((uint32_t *)&buf) ^= privp->val[i].v4; 442208946Sae break; 443208946Sae case NG_PATCH_MODE_SHL: 444208946Sae *((uint32_t *)&buf) <<= privp->val[i].v4; 445208946Sae break; 446208946Sae case NG_PATCH_MODE_SHR: 447208946Sae *((uint32_t *)&buf) >>= privp->val[i].v4; 448208946Sae break; 449208946Sae } 450208946Sae *((int32_t *)&buf) = htonl(*((int32_t *)&buf)); 451208946Sae break; 452208946Sae case 8: 453208946Sae *((int64_t *)&buf) = be64toh(*((int64_t *)&buf)); 454208946Sae switch (conf->ops[i].mode) { 455208946Sae case NG_PATCH_MODE_SET: 456208946Sae *((uint64_t *)&buf) = privp->val[i].v8; 457208946Sae break; 458208946Sae case NG_PATCH_MODE_ADD: 459208946Sae *((uint64_t *)&buf) += privp->val[i].v8; 460208946Sae break; 461208946Sae case NG_PATCH_MODE_SUB: 462208946Sae *((uint64_t *)&buf) -= privp->val[i].v8; 463208946Sae break; 464208946Sae case NG_PATCH_MODE_MUL: 465208946Sae *((uint64_t *)&buf) *= privp->val[i].v8; 466208946Sae break; 467208946Sae case NG_PATCH_MODE_DIV: 468208946Sae *((uint64_t *)&buf) /= privp->val[i].v8; 469208946Sae break; 470208946Sae case NG_PATCH_MODE_NEG: 471208946Sae *((int64_t *)&buf) = - *((int64_t *)&buf); 472208946Sae break; 473208946Sae case NG_PATCH_MODE_AND: 474208946Sae *((uint64_t *)&buf) &= privp->val[i].v8; 475208946Sae break; 476208946Sae case NG_PATCH_MODE_OR: 477208946Sae *((uint64_t *)&buf) |= privp->val[i].v8; 478208946Sae break; 479208946Sae case NG_PATCH_MODE_XOR: 480208946Sae *((uint64_t *)&buf) ^= privp->val[i].v8; 481208946Sae break; 482208946Sae case NG_PATCH_MODE_SHL: 483208946Sae *((uint64_t *)&buf) <<= privp->val[i].v8; 484208946Sae break; 485208946Sae case NG_PATCH_MODE_SHR: 486208946Sae *((uint64_t *)&buf) >>= privp->val[i].v8; 487208946Sae break; 488208946Sae } 489208946Sae *((int64_t *)&buf) = htobe64(*((int64_t *)&buf)); 490208946Sae break; 491208946Sae } 492208946Sae 493208946Sae m_copyback(m, conf->ops[i].offset, conf->ops[i].length, 494208946Sae (caddr_t)&buf); 495208946Sae patched = 1; 496208946Sae } 497208946Sae if (patched > 0) 498208946Sae privp->stats.patched++; 499208946Sae} 500208946Sae 501208946Saestatic int 502208946Saeng_patch_rcvdata(hook_p hook, item_p item) 503208946Sae{ 504208946Sae const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 505208946Sae struct mbuf *m; 506208946Sae hook_p target; 507208946Sae int error; 508208946Sae 509208946Sae priv->stats.received++; 510208946Sae NGI_GET_M(item, m); 511208946Sae if (priv->config != NULL && hook == priv->in && 512208946Sae (m->m_flags & M_PKTHDR) != 0) { 513208946Sae m = m_unshare(m,M_NOWAIT); 514208946Sae if (m == NULL) { 515208946Sae priv->stats.dropped++; 516208946Sae NG_FREE_ITEM(item); 517208946Sae return (ENOMEM); 518208946Sae } 519208946Sae do_patch(priv, m); 520234574Smelifaro m->m_pkthdr.csum_flags |= priv->config->csum_flags; 521208946Sae } 522208946Sae 523208946Sae target = NULL; 524208946Sae if (hook == priv->in) { 525208946Sae /* return frames on 'in' hook if 'out' not connected */ 526208946Sae if (priv->out != NULL) 527208946Sae target = priv->out; 528208946Sae else 529208946Sae target = priv->in; 530208946Sae } 531208946Sae if (hook == priv->out && priv->in != NULL) 532208946Sae target = priv->in; 533208946Sae 534208946Sae if (target == NULL) { 535208946Sae priv->stats.dropped++; 536208946Sae NG_FREE_ITEM(item); 537208946Sae NG_FREE_M(m); 538208946Sae return (0); 539208946Sae } 540208946Sae NG_FWD_NEW_DATA(error, item, target, m); 541208946Sae return (error); 542208946Sae} 543208946Sae 544208946Saestatic int 545208946Saeng_patch_shutdown(node_p node) 546208946Sae{ 547208946Sae const priv_p privdata = NG_NODE_PRIVATE(node); 548208946Sae 549208946Sae if (privdata->val != NULL) 550208946Sae free(privdata->val, M_NETGRAPH); 551208946Sae if (privdata->config != NULL) 552208946Sae free(privdata->config, M_NETGRAPH); 553208946Sae NG_NODE_SET_PRIVATE(node, NULL); 554208946Sae NG_NODE_UNREF(node); 555208946Sae free(privdata, M_NETGRAPH); 556208946Sae return (0); 557208946Sae} 558208946Sae 559208946Saestatic int 560208946Saeng_patch_disconnect(hook_p hook) 561208946Sae{ 562208989Sae priv_p priv; 563208946Sae 564208989Sae priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 565208946Sae if (hook == priv->in) { 566208946Sae priv->in = NULL; 567208946Sae } 568208946Sae if (hook == priv->out) { 569208946Sae priv->out = NULL; 570208946Sae } 571208989Sae if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && 572208989Sae NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */ 573208946Sae ng_rmnode_self(NG_HOOK_NODE(hook)); 574208946Sae return (0); 575208946Sae} 576208946Sae 577