1d359a62dSAndrey V. Elsukov /*- 2*bf909fc9SJulian Elischer * Copyright (c) 2010 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 { 53*bf909fc9SJulian Elischer const struct ng_patch_config *conf; 54d359a62dSAndrey V. Elsukov 55*bf909fc9SJulian Elischer conf = (const struct ng_patch_config *)(buf - 56cac2fe69SAndrey V. Elsukov offsetof(struct ng_patch_config, ops)); 57*bf909fc9SJulian Elischer 58*bf909fc9SJulian Elischer return (conf->count); 59d359a62dSAndrey V. Elsukov } 60d359a62dSAndrey V. Elsukov 61d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_op_type_fields[] 62d359a62dSAndrey V. Elsukov = NG_PATCH_OP_TYPE_INFO; 63d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_op_type = { 64d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 65d359a62dSAndrey V. Elsukov &ng_patch_op_type_fields 66d359a62dSAndrey V. Elsukov }; 67d359a62dSAndrey V. Elsukov 68*bf909fc9SJulian Elischer static const struct ng_parse_array_info ng_patch_ops_array_info = { 69d359a62dSAndrey V. Elsukov &ng_patch_op_type, 70d359a62dSAndrey V. Elsukov &ng_patch_config_getlen 71d359a62dSAndrey V. Elsukov }; 72*bf909fc9SJulian Elischer static const struct ng_parse_type ng_patch_ops_array_type = { 73d359a62dSAndrey V. Elsukov &ng_parse_array_type, 74*bf909fc9SJulian Elischer &ng_patch_ops_array_info 75d359a62dSAndrey V. Elsukov }; 76d359a62dSAndrey V. Elsukov 77d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_config_type_fields[] 78d359a62dSAndrey V. Elsukov = NG_PATCH_CONFIG_TYPE_INFO; 79d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_config_type = { 80d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 81d359a62dSAndrey V. Elsukov &ng_patch_config_type_fields 82d359a62dSAndrey V. Elsukov }; 83d359a62dSAndrey V. Elsukov 84d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_stats_fields[] 85d359a62dSAndrey V. Elsukov = NG_PATCH_STATS_TYPE_INFO; 86d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_stats_type = { 87d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 88d359a62dSAndrey V. Elsukov &ng_patch_stats_fields 89d359a62dSAndrey V. Elsukov }; 90d359a62dSAndrey V. Elsukov 91d359a62dSAndrey V. Elsukov static const struct ng_cmdlist ng_patch_cmdlist[] = { 92d359a62dSAndrey V. Elsukov { 93d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 94d359a62dSAndrey V. Elsukov NGM_PATCH_GETCONFIG, 95d359a62dSAndrey V. Elsukov "getconfig", 96d359a62dSAndrey V. Elsukov NULL, 97d359a62dSAndrey V. Elsukov &ng_patch_config_type 98d359a62dSAndrey V. Elsukov }, 99d359a62dSAndrey V. Elsukov { 100d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 101d359a62dSAndrey V. Elsukov NGM_PATCH_SETCONFIG, 102d359a62dSAndrey V. Elsukov "setconfig", 103d359a62dSAndrey V. Elsukov &ng_patch_config_type, 104d359a62dSAndrey V. Elsukov NULL 105d359a62dSAndrey V. Elsukov }, 106d359a62dSAndrey V. Elsukov { 107d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 108d359a62dSAndrey V. Elsukov NGM_PATCH_GET_STATS, 109d359a62dSAndrey V. Elsukov "getstats", 110d359a62dSAndrey V. Elsukov NULL, 111d359a62dSAndrey V. Elsukov &ng_patch_stats_type 112d359a62dSAndrey V. Elsukov }, 113d359a62dSAndrey V. Elsukov { 114d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 115d359a62dSAndrey V. Elsukov NGM_PATCH_CLR_STATS, 116d359a62dSAndrey V. Elsukov "clrstats", 117d359a62dSAndrey V. Elsukov NULL, 118d359a62dSAndrey V. Elsukov NULL 119d359a62dSAndrey V. Elsukov }, 120d359a62dSAndrey V. Elsukov { 121d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 122d359a62dSAndrey V. Elsukov NGM_PATCH_GETCLR_STATS, 123d359a62dSAndrey V. Elsukov "getclrstats", 124d359a62dSAndrey V. Elsukov NULL, 125d359a62dSAndrey V. Elsukov &ng_patch_stats_type 126d359a62dSAndrey V. Elsukov }, 127d359a62dSAndrey V. Elsukov { 0 } 128d359a62dSAndrey V. Elsukov }; 129d359a62dSAndrey V. Elsukov 130d359a62dSAndrey V. Elsukov static struct ng_type typestruct = { 131d359a62dSAndrey V. Elsukov .version = NG_ABI_VERSION, 132d359a62dSAndrey V. Elsukov .name = NG_PATCH_NODE_TYPE, 133d359a62dSAndrey V. Elsukov .constructor = ng_patch_constructor, 134d359a62dSAndrey V. Elsukov .rcvmsg = ng_patch_rcvmsg, 135d359a62dSAndrey V. Elsukov .shutdown = ng_patch_shutdown, 136d359a62dSAndrey V. Elsukov .newhook = ng_patch_newhook, 137d359a62dSAndrey V. Elsukov .rcvdata = ng_patch_rcvdata, 138d359a62dSAndrey V. Elsukov .disconnect = ng_patch_disconnect, 139d359a62dSAndrey V. Elsukov .cmdlist = ng_patch_cmdlist, 140d359a62dSAndrey V. Elsukov }; 141*bf909fc9SJulian Elischer 142d359a62dSAndrey V. Elsukov NETGRAPH_INIT(patch, &typestruct); 143d359a62dSAndrey V. Elsukov 144d359a62dSAndrey V. Elsukov union patch_val { 145d359a62dSAndrey V. Elsukov uint8_t v1; 146d359a62dSAndrey V. Elsukov uint16_t v2; 147d359a62dSAndrey V. Elsukov uint32_t v4; 148d359a62dSAndrey V. Elsukov uint64_t v8; 149d359a62dSAndrey V. Elsukov }; 150d359a62dSAndrey V. Elsukov 151*bf909fc9SJulian Elischer /* private data */ 152d359a62dSAndrey V. Elsukov struct ng_patch_priv { 153d359a62dSAndrey V. Elsukov hook_p in; 154d359a62dSAndrey V. Elsukov hook_p out; 155d359a62dSAndrey V. Elsukov struct ng_patch_config *config; 156d359a62dSAndrey V. Elsukov union patch_val *val; 157d359a62dSAndrey V. Elsukov struct ng_patch_stats stats; 158d359a62dSAndrey V. Elsukov }; 159d359a62dSAndrey V. Elsukov typedef struct ng_patch_priv *priv_p; 160d359a62dSAndrey V. Elsukov 161d359a62dSAndrey V. Elsukov #define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \ 162d359a62dSAndrey V. Elsukov (count) * sizeof(struct ng_patch_op)) 163d359a62dSAndrey V. Elsukov 164d359a62dSAndrey V. Elsukov static void do_patch(priv_p conf, struct mbuf *m); 165d359a62dSAndrey V. Elsukov 166d359a62dSAndrey V. Elsukov static int 167d359a62dSAndrey V. Elsukov ng_patch_constructor(node_p node) 168d359a62dSAndrey V. Elsukov { 169d359a62dSAndrey V. Elsukov priv_p privdata; 170d359a62dSAndrey V. Elsukov 171ffbfc0aaSAndrey V. Elsukov privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO); 172d359a62dSAndrey V. Elsukov NG_NODE_SET_PRIVATE(node, privdata); 173d359a62dSAndrey V. Elsukov privdata->in = NULL; 174d359a62dSAndrey V. Elsukov privdata->out = NULL; 175d359a62dSAndrey V. Elsukov privdata->config = NULL; 176d359a62dSAndrey V. Elsukov return (0); 177d359a62dSAndrey V. Elsukov } 178d359a62dSAndrey V. Elsukov 179d359a62dSAndrey V. Elsukov static int 180d359a62dSAndrey V. Elsukov ng_patch_newhook(node_p node, hook_p hook, const char *name) 181d359a62dSAndrey V. Elsukov { 182d359a62dSAndrey V. Elsukov const priv_p privp = NG_NODE_PRIVATE(node); 183d359a62dSAndrey V. Elsukov 184d359a62dSAndrey V. Elsukov if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) { 185d359a62dSAndrey V. Elsukov privp->in = hook; 186d359a62dSAndrey V. Elsukov } else if (strncmp(name, NG_PATCH_HOOK_OUT, 187d359a62dSAndrey V. Elsukov strlen(NG_PATCH_HOOK_OUT)) == 0) { 188d359a62dSAndrey V. Elsukov privp->out = hook; 189d359a62dSAndrey V. Elsukov } else 190d359a62dSAndrey V. Elsukov return (EINVAL); 191d359a62dSAndrey V. Elsukov return(0); 192d359a62dSAndrey V. Elsukov } 193d359a62dSAndrey V. Elsukov 194d359a62dSAndrey V. Elsukov static int 195d359a62dSAndrey V. Elsukov ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook) 196d359a62dSAndrey V. Elsukov { 197d359a62dSAndrey V. Elsukov const priv_p privp = NG_NODE_PRIVATE(node); 1986c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf, *newconf; 1996c0a2eb1SAndrey V. Elsukov union patch_val *newval; 200d359a62dSAndrey V. Elsukov struct ng_mesg *msg; 2016c0a2eb1SAndrey V. Elsukov struct ng_mesg *resp; 2026c0a2eb1SAndrey V. Elsukov int i, clear, error; 203d359a62dSAndrey V. Elsukov 2046c0a2eb1SAndrey V. Elsukov clear = error = 0; 2056c0a2eb1SAndrey V. Elsukov resp = NULL; 206d359a62dSAndrey V. Elsukov NGI_GET_MSG(item, msg); 207d359a62dSAndrey V. Elsukov switch (msg->header.typecookie) { 208d359a62dSAndrey V. Elsukov case NGM_PATCH_COOKIE: 209d359a62dSAndrey V. Elsukov switch (msg->header.cmd) { 210d359a62dSAndrey V. Elsukov case NGM_PATCH_GETCONFIG: 211d359a62dSAndrey V. Elsukov if (privp->config == NULL) 212d359a62dSAndrey V. Elsukov break; 213d359a62dSAndrey V. Elsukov NG_MKRESPONSE(resp, msg, 214ffbfc0aaSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count), 215ffbfc0aaSAndrey V. Elsukov M_WAITOK); 216d359a62dSAndrey V. Elsukov bcopy(privp->config, resp->data, 217d359a62dSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count)); 218d359a62dSAndrey V. Elsukov break; 219d359a62dSAndrey V. Elsukov case NGM_PATCH_SETCONFIG: 220d359a62dSAndrey V. Elsukov { 2216c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 2226c0a2eb1SAndrey V. Elsukov sizeof(struct ng_patch_config)) { 223d359a62dSAndrey V. Elsukov error = EINVAL; 224d359a62dSAndrey V. Elsukov break; 225d359a62dSAndrey V. Elsukov } 226d359a62dSAndrey V. Elsukov 227d359a62dSAndrey V. Elsukov conf = (struct ng_patch_config *)msg->data; 2286c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 2296c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)) { 230d359a62dSAndrey V. Elsukov error = EINVAL; 231d359a62dSAndrey V. Elsukov break; 232d359a62dSAndrey V. Elsukov } 233d359a62dSAndrey V. Elsukov 234d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 235d359a62dSAndrey V. Elsukov switch(conf->ops[i].length) { 236d359a62dSAndrey V. Elsukov case 1: 237d359a62dSAndrey V. Elsukov case 2: 238d359a62dSAndrey V. Elsukov case 4: 239d359a62dSAndrey V. Elsukov case 8: 240d359a62dSAndrey V. Elsukov break; 241d359a62dSAndrey V. Elsukov default: 242d359a62dSAndrey V. Elsukov error = EINVAL; 243d359a62dSAndrey V. Elsukov break; 244d359a62dSAndrey V. Elsukov } 245d359a62dSAndrey V. Elsukov if (error != 0) 246d359a62dSAndrey V. Elsukov break; 247d359a62dSAndrey V. Elsukov } 248d359a62dSAndrey V. Elsukov 249d359a62dSAndrey V. Elsukov conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP | 250d359a62dSAndrey V. Elsukov CSUM_SCTP; 251d359a62dSAndrey V. Elsukov 252d359a62dSAndrey V. Elsukov if (error == 0) { 2536c0a2eb1SAndrey V. Elsukov newconf = malloc( 2546c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count), 255ffbfc0aaSAndrey V. Elsukov M_NETGRAPH, M_WAITOK); 2566c0a2eb1SAndrey V. Elsukov newval = malloc(conf->count * 2576c0a2eb1SAndrey V. Elsukov sizeof(union patch_val), M_NETGRAPH, 258ffbfc0aaSAndrey V. Elsukov M_WAITOK); 259d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 260d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 261d359a62dSAndrey V. Elsukov case 1: 2626c0a2eb1SAndrey V. Elsukov newval[i].v1 = 2636c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 264d359a62dSAndrey V. Elsukov break; 265d359a62dSAndrey V. Elsukov case 2: 2666c0a2eb1SAndrey V. Elsukov newval[i].v2 = 2676c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 268d359a62dSAndrey V. Elsukov break; 269d359a62dSAndrey V. Elsukov case 4: 2706c0a2eb1SAndrey V. Elsukov newval[i].v4 = 2716c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 272d359a62dSAndrey V. Elsukov break; 273d359a62dSAndrey V. Elsukov case 8: 2746c0a2eb1SAndrey V. Elsukov newval[i].v8 = 2756c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 276d359a62dSAndrey V. Elsukov break; 277d359a62dSAndrey V. Elsukov } 278d359a62dSAndrey V. Elsukov } 2796c0a2eb1SAndrey V. Elsukov bcopy(conf, newconf, 2806c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)); 281d359a62dSAndrey V. Elsukov if (privp->val != NULL) 282d359a62dSAndrey V. Elsukov free(privp->val, M_NETGRAPH); 283d359a62dSAndrey V. Elsukov privp->val = newval; 284d359a62dSAndrey V. Elsukov if (privp->config != NULL) 285d359a62dSAndrey V. Elsukov free(privp->config, M_NETGRAPH); 286d359a62dSAndrey V. Elsukov privp->config = newconf; 287d359a62dSAndrey V. Elsukov } 288d359a62dSAndrey V. Elsukov break; 289d359a62dSAndrey V. Elsukov } 290d359a62dSAndrey V. Elsukov case NGM_PATCH_GETCLR_STATS: 291d359a62dSAndrey V. Elsukov clear = 1; 292d359a62dSAndrey V. Elsukov /* FALLTHROUGH */ 293d359a62dSAndrey V. Elsukov case NGM_PATCH_GET_STATS: 294d359a62dSAndrey V. Elsukov NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), 295ffbfc0aaSAndrey V. Elsukov M_WAITOK); 296d359a62dSAndrey V. Elsukov bcopy(&(privp->stats), resp->data, 297d359a62dSAndrey V. Elsukov sizeof(struct ng_patch_stats)); 298d359a62dSAndrey V. Elsukov if (clear == 0) 299d359a62dSAndrey V. Elsukov break; 300d359a62dSAndrey V. Elsukov /* else FALLTHROUGH */ 301d359a62dSAndrey V. Elsukov case NGM_PATCH_CLR_STATS: 302d359a62dSAndrey V. Elsukov bzero(&(privp->stats), sizeof(struct ng_patch_stats)); 303d359a62dSAndrey V. Elsukov break; 304d359a62dSAndrey V. Elsukov default: 305d359a62dSAndrey V. Elsukov error = EINVAL; 306d359a62dSAndrey V. Elsukov break; 307d359a62dSAndrey V. Elsukov } 308d359a62dSAndrey V. Elsukov break; 309d359a62dSAndrey V. Elsukov default: 310d359a62dSAndrey V. Elsukov error = EINVAL; 311d359a62dSAndrey V. Elsukov break; 312d359a62dSAndrey V. Elsukov } 313d359a62dSAndrey V. Elsukov 314d359a62dSAndrey V. Elsukov NG_RESPOND_MSG(error, node, item, resp); 315d359a62dSAndrey V. Elsukov NG_FREE_MSG(msg); 316d359a62dSAndrey V. Elsukov return(error); 317d359a62dSAndrey V. Elsukov } 318d359a62dSAndrey V. Elsukov 319d359a62dSAndrey V. Elsukov static void 320d359a62dSAndrey V. Elsukov do_patch(priv_p privp, struct mbuf *m) 321d359a62dSAndrey V. Elsukov { 3226c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf; 323d359a62dSAndrey V. Elsukov uint64_t buf; 3246c0a2eb1SAndrey V. Elsukov int i, patched; 325d359a62dSAndrey V. Elsukov 3266c0a2eb1SAndrey V. Elsukov conf = privp->config; 3276c0a2eb1SAndrey V. Elsukov patched = 0; 328d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 3296c0a2eb1SAndrey V. Elsukov if (conf->ops[i].offset + conf->ops[i].length > 3306c0a2eb1SAndrey V. Elsukov m->m_pkthdr.len) 331d359a62dSAndrey V. Elsukov continue; 332d359a62dSAndrey V. Elsukov 333d359a62dSAndrey V. Elsukov /* for "=" operation we don't need to copy data from mbuf */ 334d359a62dSAndrey V. Elsukov if (conf->ops[i].mode != NG_PATCH_MODE_SET) { 335d359a62dSAndrey V. Elsukov m_copydata(m, conf->ops[i].offset, 336d359a62dSAndrey V. Elsukov conf->ops[i].length, (caddr_t)&buf); 337d359a62dSAndrey V. Elsukov } 338d359a62dSAndrey V. Elsukov 339d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 340d359a62dSAndrey V. Elsukov case 1: 341d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 342d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 343d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) = privp->val[i].v1; 344d359a62dSAndrey V. Elsukov break; 345d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 346d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) += privp->val[i].v1; 347d359a62dSAndrey V. Elsukov break; 348d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 349d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) -= privp->val[i].v1; 350d359a62dSAndrey V. Elsukov break; 351d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 352d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) *= privp->val[i].v1; 353d359a62dSAndrey V. Elsukov break; 354d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 355d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) /= privp->val[i].v1; 356d359a62dSAndrey V. Elsukov break; 357d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 358d359a62dSAndrey V. Elsukov *((int8_t *)&buf) = - *((int8_t *)&buf); 359d359a62dSAndrey V. Elsukov break; 360d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 361d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) &= privp->val[i].v1; 362d359a62dSAndrey V. Elsukov break; 363d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 364d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) |= privp->val[i].v1; 365d359a62dSAndrey V. Elsukov break; 366d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 367d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) ^= privp->val[i].v1; 368d359a62dSAndrey V. Elsukov break; 369d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 370d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) <<= privp->val[i].v1; 371d359a62dSAndrey V. Elsukov break; 372d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 373d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) >>= privp->val[i].v1; 374d359a62dSAndrey V. Elsukov break; 375d359a62dSAndrey V. Elsukov } 376d359a62dSAndrey V. Elsukov break; 377d359a62dSAndrey V. Elsukov case 2: 378d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = ntohs(*((int16_t *)&buf)); 379d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 380d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 381d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) = privp->val[i].v2; 382d359a62dSAndrey V. Elsukov break; 383d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 384d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) += privp->val[i].v2; 385d359a62dSAndrey V. Elsukov break; 386d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 387d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) -= privp->val[i].v2; 388d359a62dSAndrey V. Elsukov break; 389d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 390d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) *= privp->val[i].v2; 391d359a62dSAndrey V. Elsukov break; 392d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 393d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) /= privp->val[i].v2; 394d359a62dSAndrey V. Elsukov break; 395d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 396d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = - *((int16_t *)&buf); 397d359a62dSAndrey V. Elsukov break; 398d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 399d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) &= privp->val[i].v2; 400d359a62dSAndrey V. Elsukov break; 401d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 402d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) |= privp->val[i].v2; 403d359a62dSAndrey V. Elsukov break; 404d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 405d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) ^= privp->val[i].v2; 406d359a62dSAndrey V. Elsukov break; 407d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 408d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) <<= privp->val[i].v2; 409d359a62dSAndrey V. Elsukov break; 410d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 411d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) >>= privp->val[i].v2; 412d359a62dSAndrey V. Elsukov break; 413d359a62dSAndrey V. Elsukov } 414d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = htons(*((int16_t *)&buf)); 415d359a62dSAndrey V. Elsukov break; 416d359a62dSAndrey V. Elsukov case 4: 417d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = ntohl(*((int32_t *)&buf)); 418d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 419d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 420d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) = privp->val[i].v4; 421d359a62dSAndrey V. Elsukov break; 422d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 423d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) += privp->val[i].v4; 424d359a62dSAndrey V. Elsukov break; 425d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 426d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) -= privp->val[i].v4; 427d359a62dSAndrey V. Elsukov break; 428d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 429d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) *= privp->val[i].v4; 430d359a62dSAndrey V. Elsukov break; 431d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 432d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) /= privp->val[i].v4; 433d359a62dSAndrey V. Elsukov break; 434d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 435d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = - *((int32_t *)&buf); 436d359a62dSAndrey V. Elsukov break; 437d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 438d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) &= privp->val[i].v4; 439d359a62dSAndrey V. Elsukov break; 440d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 441d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) |= privp->val[i].v4; 442d359a62dSAndrey V. Elsukov break; 443d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 444d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) ^= privp->val[i].v4; 445d359a62dSAndrey V. Elsukov break; 446d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 447d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) <<= privp->val[i].v4; 448d359a62dSAndrey V. Elsukov break; 449d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 450d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) >>= privp->val[i].v4; 451d359a62dSAndrey V. Elsukov break; 452d359a62dSAndrey V. Elsukov } 453d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = htonl(*((int32_t *)&buf)); 454d359a62dSAndrey V. Elsukov break; 455d359a62dSAndrey V. Elsukov case 8: 456d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = be64toh(*((int64_t *)&buf)); 457d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 458d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 459d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) = privp->val[i].v8; 460d359a62dSAndrey V. Elsukov break; 461d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 462d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) += privp->val[i].v8; 463d359a62dSAndrey V. Elsukov break; 464d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 465d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) -= privp->val[i].v8; 466d359a62dSAndrey V. Elsukov break; 467d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 468d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) *= privp->val[i].v8; 469d359a62dSAndrey V. Elsukov break; 470d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 471d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) /= privp->val[i].v8; 472d359a62dSAndrey V. Elsukov break; 473d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 474d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = - *((int64_t *)&buf); 475d359a62dSAndrey V. Elsukov break; 476d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 477d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) &= privp->val[i].v8; 478d359a62dSAndrey V. Elsukov break; 479d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 480d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) |= privp->val[i].v8; 481d359a62dSAndrey V. Elsukov break; 482d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 483d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) ^= privp->val[i].v8; 484d359a62dSAndrey V. Elsukov break; 485d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 486d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) <<= privp->val[i].v8; 487d359a62dSAndrey V. Elsukov break; 488d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 489d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) >>= privp->val[i].v8; 490d359a62dSAndrey V. Elsukov break; 491d359a62dSAndrey V. Elsukov } 492d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = htobe64(*((int64_t *)&buf)); 493d359a62dSAndrey V. Elsukov break; 494d359a62dSAndrey V. Elsukov } 495d359a62dSAndrey V. Elsukov 496d359a62dSAndrey V. Elsukov m_copyback(m, conf->ops[i].offset, conf->ops[i].length, 497d359a62dSAndrey V. Elsukov (caddr_t)&buf); 498d359a62dSAndrey V. Elsukov patched = 1; 499d359a62dSAndrey V. Elsukov } 500d359a62dSAndrey V. Elsukov if (patched > 0) 501d359a62dSAndrey V. Elsukov privp->stats.patched++; 502d359a62dSAndrey V. Elsukov } 503d359a62dSAndrey V. Elsukov 504d359a62dSAndrey V. Elsukov static int 505d359a62dSAndrey V. Elsukov ng_patch_rcvdata(hook_p hook, item_p item) 506d359a62dSAndrey V. Elsukov { 507d359a62dSAndrey V. Elsukov const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 508d359a62dSAndrey V. Elsukov struct mbuf *m; 509d359a62dSAndrey V. Elsukov hook_p target; 510d359a62dSAndrey V. Elsukov int error; 511d359a62dSAndrey V. Elsukov 512d359a62dSAndrey V. Elsukov priv->stats.received++; 513d359a62dSAndrey V. Elsukov NGI_GET_M(item, m); 514d359a62dSAndrey V. Elsukov if (priv->config != NULL && hook == priv->in && 515d359a62dSAndrey V. Elsukov (m->m_flags & M_PKTHDR) != 0) { 516d359a62dSAndrey V. Elsukov m = m_unshare(m,M_NOWAIT); 517d359a62dSAndrey V. Elsukov if (m == NULL) { 518d359a62dSAndrey V. Elsukov priv->stats.dropped++; 519d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 520d359a62dSAndrey V. Elsukov return (ENOMEM); 521d359a62dSAndrey V. Elsukov } 522d359a62dSAndrey V. Elsukov do_patch(priv, m); 5233a0cd8dbSAlexander V. Chernikov m->m_pkthdr.csum_flags |= priv->config->csum_flags; 524d359a62dSAndrey V. Elsukov } 525d359a62dSAndrey V. Elsukov 526d359a62dSAndrey V. Elsukov target = NULL; 527d359a62dSAndrey V. Elsukov if (hook == priv->in) { 528d359a62dSAndrey V. Elsukov /* return frames on 'in' hook if 'out' not connected */ 529d359a62dSAndrey V. Elsukov if (priv->out != NULL) 530d359a62dSAndrey V. Elsukov target = priv->out; 531d359a62dSAndrey V. Elsukov else 532d359a62dSAndrey V. Elsukov target = priv->in; 533d359a62dSAndrey V. Elsukov } 534d359a62dSAndrey V. Elsukov if (hook == priv->out && priv->in != NULL) 535d359a62dSAndrey V. Elsukov target = priv->in; 536d359a62dSAndrey V. Elsukov 537d359a62dSAndrey V. Elsukov if (target == NULL) { 538d359a62dSAndrey V. Elsukov priv->stats.dropped++; 539d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 540d359a62dSAndrey V. Elsukov NG_FREE_M(m); 541d359a62dSAndrey V. Elsukov return (0); 542d359a62dSAndrey V. Elsukov } 543d359a62dSAndrey V. Elsukov NG_FWD_NEW_DATA(error, item, target, m); 544d359a62dSAndrey V. Elsukov return (error); 545d359a62dSAndrey V. Elsukov } 546d359a62dSAndrey V. Elsukov 547d359a62dSAndrey V. Elsukov static int 548d359a62dSAndrey V. Elsukov ng_patch_shutdown(node_p node) 549d359a62dSAndrey V. Elsukov { 550d359a62dSAndrey V. Elsukov const priv_p privdata = NG_NODE_PRIVATE(node); 551d359a62dSAndrey V. Elsukov 552d359a62dSAndrey V. Elsukov if (privdata->val != NULL) 553d359a62dSAndrey V. Elsukov free(privdata->val, M_NETGRAPH); 554d359a62dSAndrey V. Elsukov if (privdata->config != NULL) 555d359a62dSAndrey V. Elsukov free(privdata->config, M_NETGRAPH); 556d359a62dSAndrey V. Elsukov NG_NODE_SET_PRIVATE(node, NULL); 557d359a62dSAndrey V. Elsukov NG_NODE_UNREF(node); 558d359a62dSAndrey V. Elsukov free(privdata, M_NETGRAPH); 559d359a62dSAndrey V. Elsukov return (0); 560d359a62dSAndrey V. Elsukov } 561d359a62dSAndrey V. Elsukov 562d359a62dSAndrey V. Elsukov static int 563d359a62dSAndrey V. Elsukov ng_patch_disconnect(hook_p hook) 564d359a62dSAndrey V. Elsukov { 5656c0a2eb1SAndrey V. Elsukov priv_p priv; 566d359a62dSAndrey V. Elsukov 5676c0a2eb1SAndrey V. Elsukov priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 568d359a62dSAndrey V. Elsukov if (hook == priv->in) { 569d359a62dSAndrey V. Elsukov priv->in = NULL; 570d359a62dSAndrey V. Elsukov } 571d359a62dSAndrey V. Elsukov if (hook == priv->out) { 572d359a62dSAndrey V. Elsukov priv->out = NULL; 573d359a62dSAndrey V. Elsukov } 5746c0a2eb1SAndrey V. Elsukov if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && 5756c0a2eb1SAndrey V. Elsukov NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */ 576d359a62dSAndrey V. Elsukov ng_rmnode_self(NG_HOOK_NODE(hook)); 577d359a62dSAndrey V. Elsukov return (0); 578d359a62dSAndrey V. Elsukov } 579d359a62dSAndrey V. Elsukov 580