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> 32d359a62dSAndrey V. Elsukov #include <sys/kernel.h> 33d359a62dSAndrey V. Elsukov #include <sys/ctype.h> 34d359a62dSAndrey V. Elsukov #include <sys/endian.h> /* be64toh(), htobe64() */ 35*6c0a2eb1SAndrey V. Elsukov #include <sys/errno.h> 36*6c0a2eb1SAndrey V. Elsukov #include <sys/malloc.h> 37*6c0a2eb1SAndrey V. Elsukov #include <sys/mbuf.h> 38d359a62dSAndrey V. Elsukov #include <netgraph/ng_message.h> 39d359a62dSAndrey V. Elsukov #include <netgraph/ng_parse.h> 40d359a62dSAndrey V. Elsukov #include <netgraph/ng_patch.h> 41d359a62dSAndrey V. Elsukov #include <netgraph/netgraph.h> 42d359a62dSAndrey V. Elsukov 43d359a62dSAndrey V. Elsukov static ng_constructor_t ng_patch_constructor; 44d359a62dSAndrey V. Elsukov static ng_rcvmsg_t ng_patch_rcvmsg; 45d359a62dSAndrey V. Elsukov static ng_shutdown_t ng_patch_shutdown; 46d359a62dSAndrey V. Elsukov static ng_newhook_t ng_patch_newhook; 47d359a62dSAndrey V. Elsukov static ng_rcvdata_t ng_patch_rcvdata; 48d359a62dSAndrey V. Elsukov static ng_disconnect_t ng_patch_disconnect; 49d359a62dSAndrey V. Elsukov 50d359a62dSAndrey V. Elsukov #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 51d359a62dSAndrey V. Elsukov 52d359a62dSAndrey V. Elsukov static int 53*6c0a2eb1SAndrey V. Elsukov ng_patch_config_getlen(const struct ng_parse_type *type, 54*6c0a2eb1SAndrey V. Elsukov const u_char *start, const u_char *buf) 55d359a62dSAndrey V. Elsukov { 56d359a62dSAndrey V. Elsukov const struct ng_patch_config *p; 57d359a62dSAndrey V. Elsukov 58d359a62dSAndrey V. Elsukov p = (const struct ng_patch_config *)(buf - 59d359a62dSAndrey V. Elsukov OFFSETOF(struct ng_patch_config, ops)); 60d359a62dSAndrey V. Elsukov return (p->count); 61d359a62dSAndrey V. Elsukov } 62d359a62dSAndrey V. Elsukov 63d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_op_type_fields[] 64d359a62dSAndrey V. Elsukov = NG_PATCH_OP_TYPE_INFO; 65d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_op_type = { 66d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 67d359a62dSAndrey V. Elsukov &ng_patch_op_type_fields 68d359a62dSAndrey V. Elsukov }; 69d359a62dSAndrey V. Elsukov 70d359a62dSAndrey V. Elsukov static const struct ng_parse_array_info ng_patch_confarr_info = { 71d359a62dSAndrey V. Elsukov &ng_patch_op_type, 72d359a62dSAndrey V. Elsukov &ng_patch_config_getlen 73d359a62dSAndrey V. Elsukov }; 74d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_confarr_type = { 75d359a62dSAndrey V. Elsukov &ng_parse_array_type, 76d359a62dSAndrey V. Elsukov &ng_patch_confarr_info 77d359a62dSAndrey V. Elsukov }; 78d359a62dSAndrey V. Elsukov 79d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_config_type_fields[] 80d359a62dSAndrey V. Elsukov = NG_PATCH_CONFIG_TYPE_INFO; 81d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_config_type = { 82d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 83d359a62dSAndrey V. Elsukov &ng_patch_config_type_fields 84d359a62dSAndrey V. Elsukov }; 85d359a62dSAndrey V. Elsukov 86d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_stats_fields[] 87d359a62dSAndrey V. Elsukov = NG_PATCH_STATS_TYPE_INFO; 88d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_stats_type = { 89d359a62dSAndrey V. Elsukov &ng_parse_struct_type, 90d359a62dSAndrey V. Elsukov &ng_patch_stats_fields 91d359a62dSAndrey V. Elsukov }; 92d359a62dSAndrey V. Elsukov 93d359a62dSAndrey V. Elsukov static const struct ng_cmdlist ng_patch_cmdlist[] = { 94d359a62dSAndrey V. Elsukov { 95d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 96d359a62dSAndrey V. Elsukov NGM_PATCH_GETCONFIG, 97d359a62dSAndrey V. Elsukov "getconfig", 98d359a62dSAndrey V. Elsukov NULL, 99d359a62dSAndrey V. Elsukov &ng_patch_config_type 100d359a62dSAndrey V. Elsukov }, 101d359a62dSAndrey V. Elsukov { 102d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 103d359a62dSAndrey V. Elsukov NGM_PATCH_SETCONFIG, 104d359a62dSAndrey V. Elsukov "setconfig", 105d359a62dSAndrey V. Elsukov &ng_patch_config_type, 106d359a62dSAndrey V. Elsukov NULL 107d359a62dSAndrey V. Elsukov }, 108d359a62dSAndrey V. Elsukov { 109d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 110d359a62dSAndrey V. Elsukov NGM_PATCH_GET_STATS, 111d359a62dSAndrey V. Elsukov "getstats", 112d359a62dSAndrey V. Elsukov NULL, 113d359a62dSAndrey V. Elsukov &ng_patch_stats_type 114d359a62dSAndrey V. Elsukov }, 115d359a62dSAndrey V. Elsukov { 116d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 117d359a62dSAndrey V. Elsukov NGM_PATCH_CLR_STATS, 118d359a62dSAndrey V. Elsukov "clrstats", 119d359a62dSAndrey V. Elsukov NULL, 120d359a62dSAndrey V. Elsukov NULL 121d359a62dSAndrey V. Elsukov }, 122d359a62dSAndrey V. Elsukov { 123d359a62dSAndrey V. Elsukov NGM_PATCH_COOKIE, 124d359a62dSAndrey V. Elsukov NGM_PATCH_GETCLR_STATS, 125d359a62dSAndrey V. Elsukov "getclrstats", 126d359a62dSAndrey V. Elsukov NULL, 127d359a62dSAndrey V. Elsukov &ng_patch_stats_type 128d359a62dSAndrey V. Elsukov }, 129d359a62dSAndrey V. Elsukov { 0 } 130d359a62dSAndrey V. Elsukov }; 131d359a62dSAndrey V. Elsukov 132d359a62dSAndrey V. Elsukov static struct ng_type typestruct = { 133d359a62dSAndrey V. Elsukov .version = NG_ABI_VERSION, 134d359a62dSAndrey V. Elsukov .name = NG_PATCH_NODE_TYPE, 135d359a62dSAndrey V. Elsukov .constructor = ng_patch_constructor, 136d359a62dSAndrey V. Elsukov .rcvmsg = ng_patch_rcvmsg, 137d359a62dSAndrey V. Elsukov .shutdown = ng_patch_shutdown, 138d359a62dSAndrey V. Elsukov .newhook = ng_patch_newhook, 139d359a62dSAndrey V. Elsukov .rcvdata = ng_patch_rcvdata, 140d359a62dSAndrey V. Elsukov .disconnect = ng_patch_disconnect, 141d359a62dSAndrey V. Elsukov .cmdlist = ng_patch_cmdlist, 142d359a62dSAndrey V. Elsukov }; 143d359a62dSAndrey V. Elsukov NETGRAPH_INIT(patch, &typestruct); 144d359a62dSAndrey V. Elsukov 145d359a62dSAndrey V. Elsukov union patch_val { 146d359a62dSAndrey V. Elsukov uint8_t v1; 147d359a62dSAndrey V. Elsukov uint16_t v2; 148d359a62dSAndrey V. Elsukov uint32_t v4; 149d359a62dSAndrey V. Elsukov uint64_t v8; 150d359a62dSAndrey V. Elsukov }; 151d359a62dSAndrey V. Elsukov 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 171d359a62dSAndrey V. Elsukov privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAIT | 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); 198*6c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf, *newconf; 199*6c0a2eb1SAndrey V. Elsukov union patch_val *newval; 200d359a62dSAndrey V. Elsukov struct ng_mesg *msg; 201*6c0a2eb1SAndrey V. Elsukov struct ng_mesg *resp; 202*6c0a2eb1SAndrey V. Elsukov int i, clear, error; 203d359a62dSAndrey V. Elsukov 204*6c0a2eb1SAndrey V. Elsukov clear = error = 0; 205*6c0a2eb1SAndrey 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, 214d359a62dSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count), M_WAIT); 215d359a62dSAndrey V. Elsukov bcopy(privp->config, resp->data, 216d359a62dSAndrey V. Elsukov NG_PATCH_CONF_SIZE(privp->config->count)); 217d359a62dSAndrey V. Elsukov break; 218d359a62dSAndrey V. Elsukov case NGM_PATCH_SETCONFIG: 219d359a62dSAndrey V. Elsukov { 220*6c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 221*6c0a2eb1SAndrey V. Elsukov sizeof(struct ng_patch_config)) { 222d359a62dSAndrey V. Elsukov error = EINVAL; 223d359a62dSAndrey V. Elsukov break; 224d359a62dSAndrey V. Elsukov } 225d359a62dSAndrey V. Elsukov 226d359a62dSAndrey V. Elsukov conf = (struct ng_patch_config *)msg->data; 227*6c0a2eb1SAndrey V. Elsukov if (msg->header.arglen < 228*6c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)) { 229d359a62dSAndrey V. Elsukov error = EINVAL; 230d359a62dSAndrey V. Elsukov break; 231d359a62dSAndrey V. Elsukov } 232d359a62dSAndrey V. Elsukov 233d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 234d359a62dSAndrey V. Elsukov switch(conf->ops[i].length) { 235d359a62dSAndrey V. Elsukov case 1: 236d359a62dSAndrey V. Elsukov case 2: 237d359a62dSAndrey V. Elsukov case 4: 238d359a62dSAndrey V. Elsukov case 8: 239d359a62dSAndrey V. Elsukov break; 240d359a62dSAndrey V. Elsukov default: 241d359a62dSAndrey V. Elsukov error = EINVAL; 242d359a62dSAndrey V. Elsukov break; 243d359a62dSAndrey V. Elsukov } 244d359a62dSAndrey V. Elsukov if (error != 0) 245d359a62dSAndrey V. Elsukov break; 246d359a62dSAndrey V. Elsukov } 247d359a62dSAndrey V. Elsukov 248d359a62dSAndrey V. Elsukov conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP | 249d359a62dSAndrey V. Elsukov CSUM_SCTP; 250d359a62dSAndrey V. Elsukov 251d359a62dSAndrey V. Elsukov if (error == 0) { 252*6c0a2eb1SAndrey V. Elsukov newconf = malloc( 253*6c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count), 254d359a62dSAndrey V. Elsukov M_NETGRAPH, M_WAIT); 255*6c0a2eb1SAndrey V. Elsukov newval = malloc(conf->count * 256*6c0a2eb1SAndrey V. Elsukov sizeof(union patch_val), M_NETGRAPH, 257*6c0a2eb1SAndrey V. Elsukov M_WAIT); 258d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 259d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 260d359a62dSAndrey V. Elsukov case 1: 261*6c0a2eb1SAndrey V. Elsukov newval[i].v1 = 262*6c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 263d359a62dSAndrey V. Elsukov break; 264d359a62dSAndrey V. Elsukov case 2: 265*6c0a2eb1SAndrey V. Elsukov newval[i].v2 = 266*6c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 267d359a62dSAndrey V. Elsukov break; 268d359a62dSAndrey V. Elsukov case 4: 269*6c0a2eb1SAndrey V. Elsukov newval[i].v4 = 270*6c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 271d359a62dSAndrey V. Elsukov break; 272d359a62dSAndrey V. Elsukov case 8: 273*6c0a2eb1SAndrey V. Elsukov newval[i].v8 = 274*6c0a2eb1SAndrey V. Elsukov conf->ops[i].value; 275d359a62dSAndrey V. Elsukov break; 276d359a62dSAndrey V. Elsukov } 277d359a62dSAndrey V. Elsukov } 278*6c0a2eb1SAndrey V. Elsukov bcopy(conf, newconf, 279*6c0a2eb1SAndrey V. Elsukov NG_PATCH_CONF_SIZE(conf->count)); 280d359a62dSAndrey V. Elsukov if (privp->val != NULL) 281d359a62dSAndrey V. Elsukov free(privp->val, M_NETGRAPH); 282d359a62dSAndrey V. Elsukov privp->val = newval; 283d359a62dSAndrey V. Elsukov if (privp->config != NULL) 284d359a62dSAndrey V. Elsukov free(privp->config, M_NETGRAPH); 285d359a62dSAndrey V. Elsukov privp->config = newconf; 286d359a62dSAndrey V. Elsukov } 287d359a62dSAndrey V. Elsukov break; 288d359a62dSAndrey V. Elsukov } 289d359a62dSAndrey V. Elsukov case NGM_PATCH_GETCLR_STATS: 290d359a62dSAndrey V. Elsukov clear = 1; 291d359a62dSAndrey V. Elsukov /* FALLTHROUGH */ 292d359a62dSAndrey V. Elsukov case NGM_PATCH_GET_STATS: 293d359a62dSAndrey V. Elsukov NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), 294d359a62dSAndrey V. Elsukov M_WAIT); 295d359a62dSAndrey V. Elsukov bcopy(&(privp->stats), resp->data, 296d359a62dSAndrey V. Elsukov sizeof(struct ng_patch_stats)); 297d359a62dSAndrey V. Elsukov if (clear == 0) 298d359a62dSAndrey V. Elsukov break; 299d359a62dSAndrey V. Elsukov /* else FALLTHROUGH */ 300d359a62dSAndrey V. Elsukov case NGM_PATCH_CLR_STATS: 301d359a62dSAndrey V. Elsukov bzero(&(privp->stats), sizeof(struct ng_patch_stats)); 302d359a62dSAndrey V. Elsukov break; 303d359a62dSAndrey V. Elsukov default: 304d359a62dSAndrey V. Elsukov error = EINVAL; 305d359a62dSAndrey V. Elsukov break; 306d359a62dSAndrey V. Elsukov } 307d359a62dSAndrey V. Elsukov break; 308d359a62dSAndrey V. Elsukov default: 309d359a62dSAndrey V. Elsukov error = EINVAL; 310d359a62dSAndrey V. Elsukov break; 311d359a62dSAndrey V. Elsukov } 312d359a62dSAndrey V. Elsukov 313d359a62dSAndrey V. Elsukov NG_RESPOND_MSG(error, node, item, resp); 314d359a62dSAndrey V. Elsukov NG_FREE_MSG(msg); 315d359a62dSAndrey V. Elsukov return(error); 316d359a62dSAndrey V. Elsukov } 317d359a62dSAndrey V. Elsukov 318d359a62dSAndrey V. Elsukov static void 319d359a62dSAndrey V. Elsukov do_patch(priv_p privp, struct mbuf *m) 320d359a62dSAndrey V. Elsukov { 321*6c0a2eb1SAndrey V. Elsukov struct ng_patch_config *conf; 322d359a62dSAndrey V. Elsukov uint64_t buf; 323*6c0a2eb1SAndrey V. Elsukov int i, patched; 324d359a62dSAndrey V. Elsukov 325*6c0a2eb1SAndrey V. Elsukov conf = privp->config; 326*6c0a2eb1SAndrey V. Elsukov patched = 0; 327d359a62dSAndrey V. Elsukov for(i = 0; i < conf->count; i++) { 328*6c0a2eb1SAndrey V. Elsukov if (conf->ops[i].offset + conf->ops[i].length > 329*6c0a2eb1SAndrey V. Elsukov m->m_pkthdr.len) 330d359a62dSAndrey V. Elsukov continue; 331d359a62dSAndrey V. Elsukov 332d359a62dSAndrey V. Elsukov /* for "=" operation we don't need to copy data from mbuf */ 333d359a62dSAndrey V. Elsukov if (conf->ops[i].mode != NG_PATCH_MODE_SET) { 334d359a62dSAndrey V. Elsukov m_copydata(m, conf->ops[i].offset, 335d359a62dSAndrey V. Elsukov conf->ops[i].length, (caddr_t)&buf); 336d359a62dSAndrey V. Elsukov } 337d359a62dSAndrey V. Elsukov 338d359a62dSAndrey V. Elsukov switch (conf->ops[i].length) { 339d359a62dSAndrey V. Elsukov case 1: 340d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 341d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 342d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) = privp->val[i].v1; 343d359a62dSAndrey V. Elsukov break; 344d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 345d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) += privp->val[i].v1; 346d359a62dSAndrey V. Elsukov break; 347d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 348d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) -= privp->val[i].v1; 349d359a62dSAndrey V. Elsukov break; 350d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 351d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) *= privp->val[i].v1; 352d359a62dSAndrey V. Elsukov break; 353d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 354d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) /= privp->val[i].v1; 355d359a62dSAndrey V. Elsukov break; 356d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 357d359a62dSAndrey V. Elsukov *((int8_t *)&buf) = - *((int8_t *)&buf); 358d359a62dSAndrey V. Elsukov break; 359d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 360d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) &= privp->val[i].v1; 361d359a62dSAndrey V. Elsukov break; 362d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 363d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) |= privp->val[i].v1; 364d359a62dSAndrey V. Elsukov break; 365d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 366d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) ^= privp->val[i].v1; 367d359a62dSAndrey V. Elsukov break; 368d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 369d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) <<= privp->val[i].v1; 370d359a62dSAndrey V. Elsukov break; 371d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 372d359a62dSAndrey V. Elsukov *((uint8_t *)&buf) >>= privp->val[i].v1; 373d359a62dSAndrey V. Elsukov break; 374d359a62dSAndrey V. Elsukov } 375d359a62dSAndrey V. Elsukov break; 376d359a62dSAndrey V. Elsukov case 2: 377d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = ntohs(*((int16_t *)&buf)); 378d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 379d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 380d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) = privp->val[i].v2; 381d359a62dSAndrey V. Elsukov break; 382d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 383d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) += privp->val[i].v2; 384d359a62dSAndrey V. Elsukov break; 385d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 386d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) -= privp->val[i].v2; 387d359a62dSAndrey V. Elsukov break; 388d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 389d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) *= privp->val[i].v2; 390d359a62dSAndrey V. Elsukov break; 391d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 392d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) /= privp->val[i].v2; 393d359a62dSAndrey V. Elsukov break; 394d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 395d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = - *((int16_t *)&buf); 396d359a62dSAndrey V. Elsukov break; 397d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 398d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) &= privp->val[i].v2; 399d359a62dSAndrey V. Elsukov break; 400d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 401d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) |= privp->val[i].v2; 402d359a62dSAndrey V. Elsukov break; 403d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 404d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) ^= privp->val[i].v2; 405d359a62dSAndrey V. Elsukov break; 406d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 407d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) <<= privp->val[i].v2; 408d359a62dSAndrey V. Elsukov break; 409d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 410d359a62dSAndrey V. Elsukov *((uint16_t *)&buf) >>= privp->val[i].v2; 411d359a62dSAndrey V. Elsukov break; 412d359a62dSAndrey V. Elsukov } 413d359a62dSAndrey V. Elsukov *((int16_t *)&buf) = htons(*((int16_t *)&buf)); 414d359a62dSAndrey V. Elsukov break; 415d359a62dSAndrey V. Elsukov case 4: 416d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = ntohl(*((int32_t *)&buf)); 417d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 418d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 419d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) = privp->val[i].v4; 420d359a62dSAndrey V. Elsukov break; 421d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 422d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) += privp->val[i].v4; 423d359a62dSAndrey V. Elsukov break; 424d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 425d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) -= privp->val[i].v4; 426d359a62dSAndrey V. Elsukov break; 427d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 428d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) *= privp->val[i].v4; 429d359a62dSAndrey V. Elsukov break; 430d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 431d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) /= privp->val[i].v4; 432d359a62dSAndrey V. Elsukov break; 433d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 434d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = - *((int32_t *)&buf); 435d359a62dSAndrey V. Elsukov break; 436d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 437d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) &= privp->val[i].v4; 438d359a62dSAndrey V. Elsukov break; 439d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 440d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) |= privp->val[i].v4; 441d359a62dSAndrey V. Elsukov break; 442d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 443d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) ^= privp->val[i].v4; 444d359a62dSAndrey V. Elsukov break; 445d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 446d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) <<= privp->val[i].v4; 447d359a62dSAndrey V. Elsukov break; 448d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 449d359a62dSAndrey V. Elsukov *((uint32_t *)&buf) >>= privp->val[i].v4; 450d359a62dSAndrey V. Elsukov break; 451d359a62dSAndrey V. Elsukov } 452d359a62dSAndrey V. Elsukov *((int32_t *)&buf) = htonl(*((int32_t *)&buf)); 453d359a62dSAndrey V. Elsukov break; 454d359a62dSAndrey V. Elsukov case 8: 455d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = be64toh(*((int64_t *)&buf)); 456d359a62dSAndrey V. Elsukov switch (conf->ops[i].mode) { 457d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SET: 458d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) = privp->val[i].v8; 459d359a62dSAndrey V. Elsukov break; 460d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_ADD: 461d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) += privp->val[i].v8; 462d359a62dSAndrey V. Elsukov break; 463d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SUB: 464d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) -= privp->val[i].v8; 465d359a62dSAndrey V. Elsukov break; 466d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_MUL: 467d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) *= privp->val[i].v8; 468d359a62dSAndrey V. Elsukov break; 469d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_DIV: 470d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) /= privp->val[i].v8; 471d359a62dSAndrey V. Elsukov break; 472d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_NEG: 473d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = - *((int64_t *)&buf); 474d359a62dSAndrey V. Elsukov break; 475d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_AND: 476d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) &= privp->val[i].v8; 477d359a62dSAndrey V. Elsukov break; 478d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_OR: 479d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) |= privp->val[i].v8; 480d359a62dSAndrey V. Elsukov break; 481d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_XOR: 482d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) ^= privp->val[i].v8; 483d359a62dSAndrey V. Elsukov break; 484d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHL: 485d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) <<= privp->val[i].v8; 486d359a62dSAndrey V. Elsukov break; 487d359a62dSAndrey V. Elsukov case NG_PATCH_MODE_SHR: 488d359a62dSAndrey V. Elsukov *((uint64_t *)&buf) >>= privp->val[i].v8; 489d359a62dSAndrey V. Elsukov break; 490d359a62dSAndrey V. Elsukov } 491d359a62dSAndrey V. Elsukov *((int64_t *)&buf) = htobe64(*((int64_t *)&buf)); 492d359a62dSAndrey V. Elsukov break; 493d359a62dSAndrey V. Elsukov } 494d359a62dSAndrey V. Elsukov 495d359a62dSAndrey V. Elsukov m_copyback(m, conf->ops[i].offset, conf->ops[i].length, 496d359a62dSAndrey V. Elsukov (caddr_t)&buf); 497d359a62dSAndrey V. Elsukov patched = 1; 498d359a62dSAndrey V. Elsukov } 499d359a62dSAndrey V. Elsukov if (patched > 0) 500d359a62dSAndrey V. Elsukov privp->stats.patched++; 501d359a62dSAndrey V. Elsukov } 502d359a62dSAndrey V. Elsukov 503d359a62dSAndrey V. Elsukov static int 504d359a62dSAndrey V. Elsukov ng_patch_rcvdata(hook_p hook, item_p item) 505d359a62dSAndrey V. Elsukov { 506d359a62dSAndrey V. Elsukov const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 507d359a62dSAndrey V. Elsukov struct mbuf *m; 508d359a62dSAndrey V. Elsukov hook_p target; 509d359a62dSAndrey V. Elsukov int error; 510d359a62dSAndrey V. Elsukov 511d359a62dSAndrey V. Elsukov priv->stats.received++; 512d359a62dSAndrey V. Elsukov NGI_GET_M(item, m); 513d359a62dSAndrey V. Elsukov if (priv->config != NULL && hook == priv->in && 514d359a62dSAndrey V. Elsukov (m->m_flags & M_PKTHDR) != 0) { 515d359a62dSAndrey V. Elsukov m = m_unshare(m,M_NOWAIT); 516d359a62dSAndrey V. Elsukov if (m == NULL) { 517d359a62dSAndrey V. Elsukov priv->stats.dropped++; 518d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 519d359a62dSAndrey V. Elsukov return (ENOMEM); 520d359a62dSAndrey V. Elsukov } 521d359a62dSAndrey V. Elsukov do_patch(priv, m); 522d359a62dSAndrey V. Elsukov m->m_flags |= priv->config->csum_flags; 523d359a62dSAndrey V. Elsukov } 524d359a62dSAndrey V. Elsukov 525d359a62dSAndrey V. Elsukov target = NULL; 526d359a62dSAndrey V. Elsukov if (hook == priv->in) { 527d359a62dSAndrey V. Elsukov /* return frames on 'in' hook if 'out' not connected */ 528d359a62dSAndrey V. Elsukov if (priv->out != NULL) 529d359a62dSAndrey V. Elsukov target = priv->out; 530d359a62dSAndrey V. Elsukov else 531d359a62dSAndrey V. Elsukov target = priv->in; 532d359a62dSAndrey V. Elsukov } 533d359a62dSAndrey V. Elsukov if (hook == priv->out && priv->in != NULL) 534d359a62dSAndrey V. Elsukov target = priv->in; 535d359a62dSAndrey V. Elsukov 536d359a62dSAndrey V. Elsukov if (target == NULL) { 537d359a62dSAndrey V. Elsukov priv->stats.dropped++; 538d359a62dSAndrey V. Elsukov NG_FREE_ITEM(item); 539d359a62dSAndrey V. Elsukov NG_FREE_M(m); 540d359a62dSAndrey V. Elsukov return (0); 541d359a62dSAndrey V. Elsukov } 542d359a62dSAndrey V. Elsukov NG_FWD_NEW_DATA(error, item, target, m); 543d359a62dSAndrey V. Elsukov return (error); 544d359a62dSAndrey V. Elsukov } 545d359a62dSAndrey V. Elsukov 546d359a62dSAndrey V. Elsukov static int 547d359a62dSAndrey V. Elsukov ng_patch_shutdown(node_p node) 548d359a62dSAndrey V. Elsukov { 549d359a62dSAndrey V. Elsukov const priv_p privdata = NG_NODE_PRIVATE(node); 550d359a62dSAndrey V. Elsukov 551d359a62dSAndrey V. Elsukov if (privdata->val != NULL) 552d359a62dSAndrey V. Elsukov free(privdata->val, M_NETGRAPH); 553d359a62dSAndrey V. Elsukov if (privdata->config != NULL) 554d359a62dSAndrey V. Elsukov free(privdata->config, M_NETGRAPH); 555d359a62dSAndrey V. Elsukov NG_NODE_SET_PRIVATE(node, NULL); 556d359a62dSAndrey V. Elsukov NG_NODE_UNREF(node); 557d359a62dSAndrey V. Elsukov free(privdata, M_NETGRAPH); 558d359a62dSAndrey V. Elsukov return (0); 559d359a62dSAndrey V. Elsukov } 560d359a62dSAndrey V. Elsukov 561d359a62dSAndrey V. Elsukov static int 562d359a62dSAndrey V. Elsukov ng_patch_disconnect(hook_p hook) 563d359a62dSAndrey V. Elsukov { 564*6c0a2eb1SAndrey V. Elsukov priv_p priv; 565d359a62dSAndrey V. Elsukov 566*6c0a2eb1SAndrey V. Elsukov priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 567d359a62dSAndrey V. Elsukov if (hook == priv->in) { 568d359a62dSAndrey V. Elsukov priv->in = NULL; 569d359a62dSAndrey V. Elsukov } 570d359a62dSAndrey V. Elsukov if (hook == priv->out) { 571d359a62dSAndrey V. Elsukov priv->out = NULL; 572d359a62dSAndrey V. Elsukov } 573*6c0a2eb1SAndrey V. Elsukov if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && 574*6c0a2eb1SAndrey V. Elsukov NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */ 575d359a62dSAndrey V. Elsukov ng_rmnode_self(NG_HOOK_NODE(hook)); 576d359a62dSAndrey V. Elsukov return (0); 577d359a62dSAndrey V. Elsukov } 578d359a62dSAndrey V. Elsukov 579