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