1d359a62dSAndrey V. Elsukov /*- 2d359a62dSAndrey V. Elsukov * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com> 3d359a62dSAndrey V. Elsukov * All rights reserved. 4d359a62dSAndrey V. Elsukov * 5d359a62dSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 6d359a62dSAndrey V. Elsukov * modification, are permitted provided that the following conditions 7d359a62dSAndrey V. Elsukov * are met: 8d359a62dSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 9d359a62dSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 10d359a62dSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 11d359a62dSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 12d359a62dSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 13d359a62dSAndrey V. Elsukov * 14d359a62dSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d359a62dSAndrey V. Elsukov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d359a62dSAndrey V. Elsukov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d359a62dSAndrey V. Elsukov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d359a62dSAndrey V. Elsukov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d359a62dSAndrey V. Elsukov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d359a62dSAndrey V. Elsukov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d359a62dSAndrey V. Elsukov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d359a62dSAndrey V. Elsukov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d359a62dSAndrey V. Elsukov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d359a62dSAndrey V. Elsukov * SUCH DAMAGE. 25d359a62dSAndrey V. Elsukov * 26d359a62dSAndrey V. Elsukov */ 27d359a62dSAndrey V. Elsukov 28d359a62dSAndrey V. Elsukov #include <sys/cdefs.h> 29d359a62dSAndrey V. Elsukov __FBSDID("$FreeBSD$"); 30d359a62dSAndrey V. Elsukov 31d359a62dSAndrey V. Elsukov #include <sys/param.h> 32cac2fe69SAndrey V. Elsukov #include <sys/systm.h> 33d359a62dSAndrey V. Elsukov #include <sys/kernel.h> 34cac2fe69SAndrey V. Elsukov #include <sys/endian.h> 356c0a2eb1SAndrey V. Elsukov #include <sys/malloc.h> 366c0a2eb1SAndrey V. Elsukov #include <sys/mbuf.h> 37d359a62dSAndrey V. Elsukov #include <netgraph/ng_message.h> 38d359a62dSAndrey V. Elsukov #include <netgraph/ng_parse.h> 39d359a62dSAndrey V. Elsukov #include <netgraph/ng_patch.h> 40d359a62dSAndrey V. Elsukov #include <netgraph/netgraph.h> 41d359a62dSAndrey V. Elsukov 42d359a62dSAndrey V. Elsukov static ng_constructor_t ng_patch_constructor; 43d359a62dSAndrey V. Elsukov static ng_rcvmsg_t ng_patch_rcvmsg; 44d359a62dSAndrey V. Elsukov static ng_shutdown_t ng_patch_shutdown; 45d359a62dSAndrey V. Elsukov static ng_newhook_t ng_patch_newhook; 46d359a62dSAndrey V. Elsukov static ng_rcvdata_t ng_patch_rcvdata; 47d359a62dSAndrey V. Elsukov static ng_disconnect_t ng_patch_disconnect; 48d359a62dSAndrey V. Elsukov 49d359a62dSAndrey V. Elsukov static int 506c0a2eb1SAndrey V. Elsukov ng_patch_config_getlen(const struct ng_parse_type *type, 516c0a2eb1SAndrey V. Elsukov const u_char *start, const u_char *buf) 52d359a62dSAndrey V. Elsukov { 53d359a62dSAndrey V. Elsukov const struct ng_patch_config *p; 54d359a62dSAndrey V. Elsukov 55d359a62dSAndrey V. Elsukov p = (const struct ng_patch_config *)(buf - 56cac2fe69SAndrey V. Elsukov offsetof(struct ng_patch_config, ops)); 57d359a62dSAndrey V. Elsukov return (p->count); 58d359a62dSAndrey V. Elsukov } 59d359a62dSAndrey V. Elsukov 60d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_op_type_fields[] 61d359a62dSAndrey V. Elsukov = NG_PATCH_OP_TYPE_INFO; 62d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_op_type = { 63d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 64d359a62dSAndrey V. Elsukov &ng_patch_op_type_fields 65d359a62dSAndrey V. Elsukov }; 66d359a62dSAndrey V. Elsukov 67d359a62dSAndrey V. Elsukov static const struct ng_parse_array_info ng_patch_confarr_info = { 68d359a62dSAndrey V. Elsukov &ng_patch_op_type, 69d359a62dSAndrey V. Elsukov &ng_patch_config_getlen 70d359a62dSAndrey V. Elsukov }; 71d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_confarr_type = { 72d359a62dSAndrey V. Elsukov &ng_parse_array_type, 73d359a62dSAndrey V. Elsukov &ng_patch_confarr_info 74d359a62dSAndrey V. Elsukov }; 75d359a62dSAndrey V. Elsukov 76d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_config_type_fields[] 77d359a62dSAndrey V. Elsukov = NG_PATCH_CONFIG_TYPE_INFO; 78d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_config_type = { 79d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 80d359a62dSAndrey V. Elsukov &ng_patch_config_type_fields 81d359a62dSAndrey V. Elsukov }; 82d359a62dSAndrey V. Elsukov 83d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_stats_fields[] 84d359a62dSAndrey V. Elsukov = NG_PATCH_STATS_TYPE_INFO; 85d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_stats_type = { 86d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 87d359a62dSAndrey V. Elsukov &ng_patch_stats_fields 88d359a62dSAndrey V. Elsukov }; 89d359a62dSAndrey V. Elsukov 90d359a62dSAndrey V. Elsukov static const struct ng_cmdlist ng_patch_cmdlist[] = { 91d359a62dSAndrey V. Elsukov { 92d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 93d359a62dSAndrey V. Elsukov NGM_PATCH_GETCONFIG, 94d359a62dSAndrey V. Elsukov "getconfig", 95d359a62dSAndrey V. Elsukov NULL, 96d359a62dSAndrey V. Elsukov &ng_patch_config_type 97d359a62dSAndrey V. Elsukov }, 98d359a62dSAndrey V. Elsukov { 99d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 100d359a62dSAndrey V. Elsukov NGM_PATCH_SETCONFIG, 101d359a62dSAndrey V. Elsukov "setconfig", 102d359a62dSAndrey V. Elsukov &ng_patch_config_type, 103d359a62dSAndrey V. Elsukov NULL 104d359a62dSAndrey V. Elsukov }, 105d359a62dSAndrey V. Elsukov { 106d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 107d359a62dSAndrey V. Elsukov NGM_PATCH_GET_STATS, 108d359a62dSAndrey V. Elsukov "getstats", 109d359a62dSAndrey V. Elsukov NULL, 110d359a62dSAndrey V. Elsukov &ng_patch_stats_type 111d359a62dSAndrey V. Elsukov }, 112d359a62dSAndrey V. Elsukov { 113d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 114d359a62dSAndrey V. Elsukov NGM_PATCH_CLR_STATS, 115d359a62dSAndrey V. Elsukov "clrstats", 116d359a62dSAndrey V. Elsukov NULL, 117d359a62dSAndrey V. Elsukov NULL 118d359a62dSAndrey V. Elsukov }, 119d359a62dSAndrey V. Elsukov { 120d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 121d359a62dSAndrey V. Elsukov NGM_PATCH_GETCLR_STATS, 122d359a62dSAndrey V. Elsukov "getclrstats", 123d359a62dSAndrey V. Elsukov NULL, 124d359a62dSAndrey V. Elsukov &ng_patch_stats_type 125d359a62dSAndrey V. Elsukov }, 126d359a62dSAndrey V. Elsukov { 0 } 127d359a62dSAndrey V. Elsukov }; 128d359a62dSAndrey V. Elsukov 129d359a62dSAndrey V. Elsukov static struct ng_type typestruct = { 130d359a62dSAndrey V. Elsukov .version = NG_ABI_VERSION, 131d359a62dSAndrey V. Elsukov .name = NG_PATCH_NODE_TYPE, 132d359a62dSAndrey V. Elsukov .constructor = ng_patch_constructor, 133d359a62dSAndrey V. Elsukov .rcvmsg = ng_patch_rcvmsg, 134d359a62dSAndrey V. Elsukov .shutdown = ng_patch_shutdown, 135d359a62dSAndrey V. Elsukov .newhook = ng_patch_newhook, 136d359a62dSAndrey V. Elsukov .rcvdata = ng_patch_rcvdata, 137d359a62dSAndrey V. Elsukov .disconnect = ng_patch_disconnect, 138d359a62dSAndrey V. Elsukov .cmdlist = ng_patch_cmdlist, 139d359a62dSAndrey V. Elsukov }; 140d359a62dSAndrey V. Elsukov NETGRAPH_INIT(patch, &typestruct); 141d359a62dSAndrey V. Elsukov 142d359a62dSAndrey V. Elsukov union patch_val { 143d359a62dSAndrey V. Elsukov uint8_t v1; 144d359a62dSAndrey V. Elsukov uint16_t v2; 145d359a62dSAndrey V. Elsukov uint32_t v4; 146d359a62dSAndrey V. Elsukov uint64_t v8; 147d359a62dSAndrey V. Elsukov }; 148d359a62dSAndrey V. Elsukov 149d359a62dSAndrey V. Elsukov struct ng_patch_priv { 150d359a62dSAndrey V. Elsukov hook_p in; 151d359a62dSAndrey V. Elsukov hook_p out; 152d359a62dSAndrey V. Elsukov struct ng_patch_config *config; 153d359a62dSAndrey V. Elsukov union patch_val *val; 154d359a62dSAndrey V. Elsukov struct ng_patch_stats stats; 155d359a62dSAndrey V. Elsukov }; 156d359a62dSAndrey V. Elsukov typedef struct ng_patch_priv *priv_p; 157d359a62dSAndrey V. Elsukov 158d359a62dSAndrey V. Elsukov #define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \ 159d359a62dSAndrey V. Elsukov (count) * sizeof(struct ng_patch_op)) 160d359a62dSAndrey V. Elsukov 161d359a62dSAndrey V. Elsukov static void do_patch(priv_p conf, struct mbuf *m); 162d359a62dSAndrey V. Elsukov 163d359a62dSAndrey V. Elsukov static int 164d359a62dSAndrey V. Elsukov ng_patch_constructor(node_p node) 165d359a62dSAndrey V. Elsukov { 166d359a62dSAndrey V. Elsukov priv_p privdata; 167d359a62dSAndrey V. Elsukov 168*ffbfc0aaSAndrey V. Elsukov privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO); 169d359a62dSAndrey V. Elsukov NG_NODE_SET_PRIVATE(node, privdata); 170d359a62dSAndrey V. Elsukov privdata->in = NULL; 171d359a62dSAndrey V. Elsukov privdata->out = NULL; 172d359a62dSAndrey V. Elsukov privdata->config = NULL; 173d359a62dSAndrey V. Elsukov return (0); 174d359a62dSAndrey V. Elsukov } 175d359a62dSAndrey V. Elsukov 176d359a62dSAndrey V. Elsukov static int 177d359a62dSAndrey V. Elsukov ng_patch_newhook(node_p node, hook_p hook, const char *name) 178d359a62dSAndrey V. Elsukov { 179d359a62dSAndrey V. Elsukov const priv_p privp = NG_NODE_PRIVATE(node); 180d359a62dSAndrey V. Elsukov 181d359a62dSAndrey V. Elsukov if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) { 182d359a62dSAndrey V. Elsukov privp->in = hook; 183d359a62dSAndrey V. Elsukov } else if (strncmp(name, NG_PATCH_HOOK_OUT, 184d359a62dSAndrey V. Elsukov strlen(NG_PATCH_HOOK_OUT)) == 0) { 185d359a62dSAndrey V. Elsukov privp->out = hook; 186d359a62dSAndrey V. Elsukov } else 187d359a62dSAndrey V. Elsukov return (EINVAL); 188d359a62dSAndrey V. Elsukov return(0); 189d359a62dSAndrey V. Elsukov } 190d359a62dSAndrey V. Elsukov 191d359a62dSAndrey V. Elsukov static int 192d359a62dSAndrey V. Elsukov ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook) 193d359a62dSAndrey V. Elsukov { 194d359a62dSAndrey V. Elsukov const priv_p privp = NG_NODE_PRIVATE(node); 1956c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf, *newconf; 1966c0a2eb1SAndrey V. Elsukov union patch_val *newval; 197d359a62dSAndrey V. Elsukov struct ng_mesg *msg; 1986c0a2eb1SAndrey V. Elsukov struct ng_mesg *resp; 1996c0a2eb1SAndrey V. Elsukov int i, clear, error; 200d359a62dSAndrey V. Elsukov 2016c0a2eb1SAndrey V. Elsukov clear = error = 0; 2026c0a2eb1SAndrey V. Elsukov resp = NULL; 203d359a62dSAndrey V. Elsukov NGI_GET_MSG(item, msg); 204d359a62dSAndrey V. Elsukov switch (msg->header.typecookie) { 205d359a62dSAndrey V. Elsukov case NGM_PATCH_COOKIE: 206d359a62dSAndrey V. Elsukov switch (msg->header.cmd) { 207d359a62dSAndrey V. Elsukov case NGM_PATCH_GETCONFIG: 208d359a62dSAndrey V. Elsukov if (privp->config == NULL) 209d359a62dSAndrey V. Elsukov break; 210d359a62dSAndrey V. Elsukov NG_MKRESPONSE(resp, msg, 211*ffbfc0aaSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count), 212*ffbfc0aaSAndrey V. Elsukov M_WAITOK); 213d359a62dSAndrey V. Elsukov bcopy(privp->config, resp->data, 214d359a62dSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count)); 215d359a62dSAndrey V. Elsukov break; 216d359a62dSAndrey V. Elsukov case NGM_PATCH_SETCONFIG: 217d359a62dSAndrey V. Elsukov { 2186c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 2196c0a2eb1SAndrey V. Elsukov sizeof(struct ng_patch_config)) { 220d359a62dSAndrey V. Elsukov error = EINVAL; 221d359a62dSAndrey V. Elsukov break; 222d359a62dSAndrey V. Elsukov } 223d359a62dSAndrey V. Elsukov 224d359a62dSAndrey V. Elsukov conf = (struct ng_patch_config *)msg->data; 2256c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 2266c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)) { 227d359a62dSAndrey V. Elsukov error = EINVAL; 228d359a62dSAndrey V. Elsukov break; 229d359a62dSAndrey V. Elsukov } 230d359a62dSAndrey V. Elsukov 231d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 232d359a62dSAndrey V. Elsukov switch(conf->ops[i].length) { 233d359a62dSAndrey V. Elsukov case 1: 234d359a62dSAndrey V. Elsukov case 2: 235d359a62dSAndrey V. Elsukov case 4: 236d359a62dSAndrey V. Elsukov case 8: 237d359a62dSAndrey V. Elsukov break; 238d359a62dSAndrey V. Elsukov default: 239d359a62dSAndrey V. Elsukov error = EINVAL; 240d359a62dSAndrey V. Elsukov break; 241d359a62dSAndrey V. Elsukov } 242d359a62dSAndrey V. Elsukov if (error != 0) 243d359a62dSAndrey V. Elsukov break; 244d359a62dSAndrey V. Elsukov } 245d359a62dSAndrey V. Elsukov 246d359a62dSAndrey V. Elsukov conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP | 247d359a62dSAndrey V. Elsukov CSUM_SCTP; 248d359a62dSAndrey V. Elsukov 249d359a62dSAndrey V. Elsukov if (error == 0) { 2506c0a2eb1SAndrey V. Elsukov newconf = malloc( 2516c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count), 252*ffbfc0aaSAndrey V. Elsukov M_NETGRAPH, M_WAITOK); 2536c0a2eb1SAndrey V. Elsukov newval = malloc(conf->count * 2546c0a2eb1SAndrey V. Elsukov sizeof(union patch_val), M_NETGRAPH, 255*ffbfc0aaSAndrey V. Elsukov M_WAITOK); 256d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 257d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 258d359a62dSAndrey V. Elsukov case 1: 2596c0a2eb1SAndrey V. Elsukov newval[i].v1 = 2606c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 261d359a62dSAndrey V. Elsukov break; 262d359a62dSAndrey V. Elsukov case 2: 2636c0a2eb1SAndrey V. Elsukov newval[i].v2 = 2646c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 265d359a62dSAndrey V. Elsukov break; 266d359a62dSAndrey V. Elsukov case 4: 2676c0a2eb1SAndrey V. Elsukov newval[i].v4 = 2686c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 269d359a62dSAndrey V. Elsukov break; 270d359a62dSAndrey V. Elsukov case 8: 2716c0a2eb1SAndrey V. Elsukov newval[i].v8 = 2726c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 273d359a62dSAndrey V. Elsukov break; 274d359a62dSAndrey V. Elsukov } 275d359a62dSAndrey V. Elsukov } 2766c0a2eb1SAndrey V. Elsukov bcopy(conf, newconf, 2776c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)); 278d359a62dSAndrey V. Elsukov if (privp->val != NULL) 279d359a62dSAndrey V. Elsukov free(privp->val, M_NETGRAPH); 280d359a62dSAndrey V. Elsukov privp->val = newval; 281d359a62dSAndrey V. Elsukov if (privp->config != NULL) 282d359a62dSAndrey V. Elsukov free(privp->config, M_NETGRAPH); 283d359a62dSAndrey V. Elsukov privp->config = newconf; 284d359a62dSAndrey V. Elsukov } 285d359a62dSAndrey V. Elsukov break; 286d359a62dSAndrey V. Elsukov } 287d359a62dSAndrey V. Elsukov case NGM_PATCH_GETCLR_STATS: 288d359a62dSAndrey V. Elsukov clear = 1; 289d359a62dSAndrey V. Elsukov /* FALLTHROUGH */ 290d359a62dSAndrey V. Elsukov case NGM_PATCH_GET_STATS: 291d359a62dSAndrey V. Elsukov NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), 292*ffbfc0aaSAndrey V. Elsukov M_WAITOK); 293d359a62dSAndrey V. Elsukov bcopy(&(privp->stats), resp->data, 294d359a62dSAndrey V. Elsukov sizeof(struct ng_patch_stats)); 295d359a62dSAndrey V. Elsukov if (clear == 0) 296d359a62dSAndrey V. Elsukov break; 297d359a62dSAndrey V. Elsukov /* else FALLTHROUGH */ 298d359a62dSAndrey V. Elsukov case NGM_PATCH_CLR_STATS: 299d359a62dSAndrey V. Elsukov bzero(&(privp->stats), sizeof(struct ng_patch_stats)); 300d359a62dSAndrey V. Elsukov break; 301d359a62dSAndrey V. Elsukov default: 302d359a62dSAndrey V. Elsukov error = EINVAL; 303d359a62dSAndrey V. Elsukov break; 304d359a62dSAndrey V. Elsukov } 305d359a62dSAndrey V. Elsukov break; 306d359a62dSAndrey V. Elsukov default: 307d359a62dSAndrey V. Elsukov error = EINVAL; 308d359a62dSAndrey V. Elsukov break; 309d359a62dSAndrey V. Elsukov } 310d359a62dSAndrey V. Elsukov 311d359a62dSAndrey V. Elsukov NG_RESPOND_MSG(error, node, item, resp); 312d359a62dSAndrey V. Elsukov NG_FREE_MSG(msg); 313d359a62dSAndrey V. Elsukov return(error); 314d359a62dSAndrey V. Elsukov } 315d359a62dSAndrey V. Elsukov 316d359a62dSAndrey V. Elsukov static void 317d359a62dSAndrey V. Elsukov do_patch(priv_p privp, struct mbuf *m) 318d359a62dSAndrey V. Elsukov { 3196c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf; 320d359a62dSAndrey V. Elsukov uint64_t buf; 3216c0a2eb1SAndrey V. Elsukov int i, patched; 322d359a62dSAndrey V. Elsukov 3236c0a2eb1SAndrey V. Elsukov conf = privp->config; 3246c0a2eb1SAndrey V. Elsukov patched = 0; 325d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 3266c0a2eb1SAndrey V. Elsukov if (conf->ops[i].offset + conf->ops[i].length > 3276c0a2eb1SAndrey V. Elsukov m->m_pkthdr.len) 328d359a62dSAndrey V. Elsukov continue; 329d359a62dSAndrey V. Elsukov 330d359a62dSAndrey V. Elsukov /* for "=" operation we don't need to copy data from mbuf */ 331d359a62dSAndrey V. Elsukov if (conf->ops[i].mode != NG_PATCH_MODE_SET) { 332d359a62dSAndrey V. Elsukov m_copydata(m, conf->ops[i].offset, 333d359a62dSAndrey V. Elsukov conf->ops[i].length, (caddr_t)&buf); 334d359a62dSAndrey V. Elsukov } 335d359a62dSAndrey V. Elsukov 336d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 337d359a62dSAndrey V. Elsukov case 1: 338d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 339d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 340d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) = privp->val[i].v1; 341d359a62dSAndrey V. Elsukov break; 342d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 343d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) += privp->val[i].v1; 344d359a62dSAndrey V. Elsukov break; 345d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 346d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) -= privp->val[i].v1; 347d359a62dSAndrey V. Elsukov break; 348d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 349d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) *= privp->val[i].v1; 350d359a62dSAndrey V. Elsukov break; 351d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 352d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) /= privp->val[i].v1; 353d359a62dSAndrey V. Elsukov break; 354d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 355d359a62dSAndrey V. Elsukov *((int8_t *)&buf) = - *((int8_t *)&buf); 356d359a62dSAndrey V. Elsukov break; 357d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 358d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) &= privp->val[i].v1; 359d359a62dSAndrey V. Elsukov break; 360d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 361d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) |= privp->val[i].v1; 362d359a62dSAndrey V. Elsukov break; 363d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 364d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) ^= privp->val[i].v1; 365d359a62dSAndrey V. Elsukov break; 366d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 367d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) <<= privp->val[i].v1; 368d359a62dSAndrey V. Elsukov break; 369d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 370d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) >>= privp->val[i].v1; 371d359a62dSAndrey V. Elsukov break; 372d359a62dSAndrey V. Elsukov } 373d359a62dSAndrey V. Elsukov break; 374d359a62dSAndrey V. Elsukov case 2: 375d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = ntohs(*((int16_t *)&buf)); 376d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 377d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 378d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) = privp->val[i].v2; 379d359a62dSAndrey V. Elsukov break; 380d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 381d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) += privp->val[i].v2; 382d359a62dSAndrey V. Elsukov break; 383d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 384d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) -= privp->val[i].v2; 385d359a62dSAndrey V. Elsukov break; 386d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 387d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) *= privp->val[i].v2; 388d359a62dSAndrey V. Elsukov break; 389d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 390d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) /= privp->val[i].v2; 391d359a62dSAndrey V. Elsukov break; 392d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 393d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = - *((int16_t *)&buf); 394d359a62dSAndrey V. Elsukov break; 395d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 396d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) &= privp->val[i].v2; 397d359a62dSAndrey V. Elsukov break; 398d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 399d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) |= privp->val[i].v2; 400d359a62dSAndrey V. Elsukov break; 401d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 402d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) ^= privp->val[i].v2; 403d359a62dSAndrey V. Elsukov break; 404d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 405d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) <<= privp->val[i].v2; 406d359a62dSAndrey V. Elsukov break; 407d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 408d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) >>= privp->val[i].v2; 409d359a62dSAndrey V. Elsukov break; 410d359a62dSAndrey V. Elsukov } 411d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = htons(*((int16_t *)&buf)); 412d359a62dSAndrey V. Elsukov break; 413d359a62dSAndrey V. Elsukov case 4: 414d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = ntohl(*((int32_t *)&buf)); 415d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 416d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 417d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) = privp->val[i].v4; 418d359a62dSAndrey V. Elsukov break; 419d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 420d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) += privp->val[i].v4; 421d359a62dSAndrey V. Elsukov break; 422d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 423d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) -= privp->val[i].v4; 424d359a62dSAndrey V. Elsukov break; 425d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 426d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) *= privp->val[i].v4; 427d359a62dSAndrey V. Elsukov break; 428d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 429d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) /= privp->val[i].v4; 430d359a62dSAndrey V. Elsukov break; 431d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 432d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = - *((int32_t *)&buf); 433d359a62dSAndrey V. Elsukov break; 434d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 435d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) &= privp->val[i].v4; 436d359a62dSAndrey V. Elsukov break; 437d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 438d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) |= privp->val[i].v4; 439d359a62dSAndrey V. Elsukov break; 440d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 441d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) ^= privp->val[i].v4; 442d359a62dSAndrey V. Elsukov break; 443d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 444d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) <<= privp->val[i].v4; 445d359a62dSAndrey V. Elsukov break; 446d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 447d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) >>= privp->val[i].v4; 448d359a62dSAndrey V. Elsukov break; 449d359a62dSAndrey V. Elsukov } 450d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = htonl(*((int32_t *)&buf)); 451d359a62dSAndrey V. Elsukov break; 452d359a62dSAndrey V. Elsukov case 8: 453d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = be64toh(*((int64_t *)&buf)); 454d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 455d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 456d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) = privp->val[i].v8; 457d359a62dSAndrey V. Elsukov break; 458d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 459d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) += privp->val[i].v8; 460d359a62dSAndrey V. Elsukov break; 461d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 462d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) -= privp->val[i].v8; 463d359a62dSAndrey V. Elsukov break; 464d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 465d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) *= privp->val[i].v8; 466d359a62dSAndrey V. Elsukov break; 467d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 468d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) /= privp->val[i].v8; 469d359a62dSAndrey V. Elsukov break; 470d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 471d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = - *((int64_t *)&buf); 472d359a62dSAndrey V. Elsukov break; 473d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 474d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) &= privp->val[i].v8; 475d359a62dSAndrey V. Elsukov break; 476d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 477d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) |= privp->val[i].v8; 478d359a62dSAndrey V. Elsukov break; 479d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 480d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) ^= privp->val[i].v8; 481d359a62dSAndrey V. Elsukov break; 482d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 483d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) <<= privp->val[i].v8; 484d359a62dSAndrey V. Elsukov break; 485d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 486d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) >>= privp->val[i].v8; 487d359a62dSAndrey V. Elsukov break; 488d359a62dSAndrey V. Elsukov } 489d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = htobe64(*((int64_t *)&buf)); 490d359a62dSAndrey V. Elsukov break; 491d359a62dSAndrey V. Elsukov } 492d359a62dSAndrey V. Elsukov 493d359a62dSAndrey V. Elsukov m_copyback(m, conf->ops[i].offset, conf->ops[i].length, 494d359a62dSAndrey V. Elsukov (caddr_t)&buf); 495d359a62dSAndrey V. Elsukov patched = 1; 496d359a62dSAndrey V. Elsukov } 497d359a62dSAndrey V. Elsukov if (patched > 0) 498d359a62dSAndrey V. Elsukov privp->stats.patched++; 499d359a62dSAndrey V. Elsukov } 500d359a62dSAndrey V. Elsukov 501d359a62dSAndrey V. Elsukov static int 502d359a62dSAndrey V. Elsukov ng_patch_rcvdata(hook_p hook, item_p item) 503d359a62dSAndrey V. Elsukov { 504d359a62dSAndrey V. Elsukov const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 505d359a62dSAndrey V. Elsukov struct mbuf *m; 506d359a62dSAndrey V. Elsukov hook_p target; 507d359a62dSAndrey V. Elsukov int error; 508d359a62dSAndrey V. Elsukov 509d359a62dSAndrey V. Elsukov priv->stats.received++; 510d359a62dSAndrey V. Elsukov NGI_GET_M(item, m); 511d359a62dSAndrey V. Elsukov if (priv->config != NULL && hook == priv->in && 512d359a62dSAndrey V. Elsukov (m->m_flags & M_PKTHDR) != 0) { 513d359a62dSAndrey V. Elsukov m = m_unshare(m,M_NOWAIT); 514d359a62dSAndrey V. Elsukov if (m == NULL) { 515d359a62dSAndrey V. Elsukov priv->stats.dropped++; 516d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 517d359a62dSAndrey V. Elsukov return (ENOMEM); 518d359a62dSAndrey V. Elsukov } 519d359a62dSAndrey V. Elsukov do_patch(priv, m); 520d359a62dSAndrey V. Elsukov m->m_flags |= priv->config->csum_flags; 521d359a62dSAndrey V. Elsukov } 522d359a62dSAndrey V. Elsukov 523d359a62dSAndrey V. Elsukov target = NULL; 524d359a62dSAndrey V. Elsukov if (hook == priv->in) { 525d359a62dSAndrey V. Elsukov /* return frames on 'in' hook if 'out' not connected */ 526d359a62dSAndrey V. Elsukov if (priv->out != NULL) 527d359a62dSAndrey V. Elsukov target = priv->out; 528d359a62dSAndrey V. Elsukov else 529d359a62dSAndrey V. Elsukov target = priv->in; 530d359a62dSAndrey V. Elsukov } 531d359a62dSAndrey V. Elsukov if (hook == priv->out && priv->in != NULL) 532d359a62dSAndrey V. Elsukov target = priv->in; 533d359a62dSAndrey V. Elsukov 534d359a62dSAndrey V. Elsukov if (target == NULL) { 535d359a62dSAndrey V. Elsukov priv->stats.dropped++; 536d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 537d359a62dSAndrey V. Elsukov NG_FREE_M(m); 538d359a62dSAndrey V. Elsukov return (0); 539d359a62dSAndrey V. Elsukov } 540d359a62dSAndrey V. Elsukov NG_FWD_NEW_DATA(error, item, target, m); 541d359a62dSAndrey V. Elsukov return (error); 542d359a62dSAndrey V. Elsukov } 543d359a62dSAndrey V. Elsukov 544d359a62dSAndrey V. Elsukov static int 545d359a62dSAndrey V. Elsukov ng_patch_shutdown(node_p node) 546d359a62dSAndrey V. Elsukov { 547d359a62dSAndrey V. Elsukov const priv_p privdata = NG_NODE_PRIVATE(node); 548d359a62dSAndrey V. Elsukov 549d359a62dSAndrey V. Elsukov if (privdata->val != NULL) 550d359a62dSAndrey V. Elsukov free(privdata->val, M_NETGRAPH); 551d359a62dSAndrey V. Elsukov if (privdata->config != NULL) 552d359a62dSAndrey V. Elsukov free(privdata->config, M_NETGRAPH); 553d359a62dSAndrey V. Elsukov NG_NODE_SET_PRIVATE(node, NULL); 554d359a62dSAndrey V. Elsukov NG_NODE_UNREF(node); 555d359a62dSAndrey V. Elsukov free(privdata, M_NETGRAPH); 556d359a62dSAndrey V. Elsukov return (0); 557d359a62dSAndrey V. Elsukov } 558d359a62dSAndrey V. Elsukov 559d359a62dSAndrey V. Elsukov static int 560d359a62dSAndrey V. Elsukov ng_patch_disconnect(hook_p hook) 561d359a62dSAndrey V. Elsukov { 5626c0a2eb1SAndrey V. Elsukov priv_p priv; 563d359a62dSAndrey V. Elsukov 5646c0a2eb1SAndrey V. Elsukov priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 565d359a62dSAndrey V. Elsukov if (hook == priv->in) { 566d359a62dSAndrey V. Elsukov priv->in = NULL; 567d359a62dSAndrey V. Elsukov } 568d359a62dSAndrey V. Elsukov if (hook == priv->out) { 569d359a62dSAndrey V. Elsukov priv->out = NULL; 570d359a62dSAndrey V. Elsukov } 5716c0a2eb1SAndrey V. Elsukov if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && 5726c0a2eb1SAndrey V. Elsukov NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */ 573d359a62dSAndrey V. Elsukov ng_rmnode_self(NG_HOOK_NODE(hook)); 574d359a62dSAndrey V. Elsukov return (0); 575d359a62dSAndrey V. Elsukov } 576d359a62dSAndrey V. Elsukov 577