1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/systm.h> 30*0Sstevel@tonic-gate #include <sys/socket.h> 31*0Sstevel@tonic-gate #include <netinet/in.h> 32*0Sstevel@tonic-gate #include <sys/modctl.h> 33*0Sstevel@tonic-gate #include <sys/sunddi.h> 34*0Sstevel@tonic-gate #include <ipp/ipp.h> 35*0Sstevel@tonic-gate #include <ipp/ipp_config.h> 36*0Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h> 37*0Sstevel@tonic-gate #include <inet/ip.h> 38*0Sstevel@tonic-gate #include <net/if.h> 39*0Sstevel@tonic-gate #include <inet/ip_if.h> 40*0Sstevel@tonic-gate #include <inet/ipp_common.h> 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* DDI file for ipgpc ipp module */ 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate /* protects against multiple configs */ 45*0Sstevel@tonic-gate static kmutex_t ipgpc_config_lock; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 48*0Sstevel@tonic-gate static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 49*0Sstevel@tonic-gate static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t); 50*0Sstevel@tonic-gate static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *, 51*0Sstevel@tonic-gate ipp_flags_t); 52*0Sstevel@tonic-gate static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *); 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate ipp_ops_t ipgpc_ops = { 55*0Sstevel@tonic-gate IPPO_REV, 56*0Sstevel@tonic-gate ipgpc_create_action, /* ippo_action_create */ 57*0Sstevel@tonic-gate ipgpc_modify_action, /* ippo_action_modify */ 58*0Sstevel@tonic-gate ipgpc_destroy_action, /* ippo_action_destroy */ 59*0Sstevel@tonic-gate ipgpc_info, /* ippo_action_info */ 60*0Sstevel@tonic-gate ipgpc_invoke_action /* ippo_action_invoke */ 61*0Sstevel@tonic-gate }; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate extern struct mod_ops mod_ippops; 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate /* 66*0Sstevel@tonic-gate * Module linkage information for the kernel. 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate static struct modlipp modlipp = { 69*0Sstevel@tonic-gate &mod_ippops, 70*0Sstevel@tonic-gate "IP Generic Packet Classifier (ipgpc) module 1.0", 71*0Sstevel@tonic-gate &ipgpc_ops 72*0Sstevel@tonic-gate }; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 75*0Sstevel@tonic-gate MODREV_1, 76*0Sstevel@tonic-gate (void *)&modlipp, 77*0Sstevel@tonic-gate NULL 78*0Sstevel@tonic-gate }; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate #define __FN__ "_init" 81*0Sstevel@tonic-gate int 82*0Sstevel@tonic-gate _init( 83*0Sstevel@tonic-gate void) 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate int rc; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate if (ipgpc_action_exist) { 88*0Sstevel@tonic-gate return (EBUSY); 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate /* init mutexes */ 91*0Sstevel@tonic-gate mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL); 92*0Sstevel@tonic-gate mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL); 93*0Sstevel@tonic-gate mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL); 94*0Sstevel@tonic-gate mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL); 95*0Sstevel@tonic-gate mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL); 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) != 0) { 98*0Sstevel@tonic-gate /* clean up after fail */ 99*0Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 100*0Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 101*0Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 102*0Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 103*0Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate return (rc); 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate #undef __FN__ 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate #define __FN__ "_fini" 111*0Sstevel@tonic-gate int 112*0Sstevel@tonic-gate _fini( 113*0Sstevel@tonic-gate void) 114*0Sstevel@tonic-gate { 115*0Sstevel@tonic-gate int rc; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate if (ipgpc_action_exist) { 118*0Sstevel@tonic-gate return (EBUSY); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate if ((rc = mod_remove(&modlinkage)) != 0) { 122*0Sstevel@tonic-gate return (rc); 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate /* destroy mutexes */ 125*0Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 126*0Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 127*0Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 128*0Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 129*0Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 130*0Sstevel@tonic-gate return (rc); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate #undef __FN__ 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate #define __FN__ "_info" 135*0Sstevel@tonic-gate int 136*0Sstevel@tonic-gate _info( 137*0Sstevel@tonic-gate struct modinfo *modinfop) 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate #undef __FN__ 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * ipgpc_create_action(aid, nvlpp, flags) 145*0Sstevel@tonic-gate * 146*0Sstevel@tonic-gate * creates a single instance of ipgpc, if one does not exist. If an action 147*0Sstevel@tonic-gate * instance already exists, fail with EBUSY 148*0Sstevel@tonic-gate * 149*0Sstevel@tonic-gate * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and 150*0Sstevel@tonic-gate * determine if global stats should be collected 151*0Sstevel@tonic-gate * 152*0Sstevel@tonic-gate * the ipgpc_config_lock is taken to block out any other creates or destroys 153*0Sstevel@tonic-gate * the are issued while the create is taking place 154*0Sstevel@tonic-gate */ 155*0Sstevel@tonic-gate /* ARGSUSED */ 156*0Sstevel@tonic-gate static int 157*0Sstevel@tonic-gate ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 158*0Sstevel@tonic-gate { 159*0Sstevel@tonic-gate int rc; 160*0Sstevel@tonic-gate uint32_t stat; 161*0Sstevel@tonic-gate nvlist_t *nvlp; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate nvlp = *nvlpp; 164*0Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* only one ipgpc action instance can be loaded at once */ 167*0Sstevel@tonic-gate if (ipgpc_action_exist) { 168*0Sstevel@tonic-gate nvlist_free(nvlp); 169*0Sstevel@tonic-gate return (EBUSY); 170*0Sstevel@tonic-gate } else { 171*0Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 172*0Sstevel@tonic-gate if (ipgpc_action_exist) { 173*0Sstevel@tonic-gate nvlist_free(nvlp); 174*0Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 175*0Sstevel@tonic-gate return (EBUSY); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate /* check for action param IPP_ACTION_STATS_ENABLE */ 178*0Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 179*0Sstevel@tonic-gate &stat)) != 0) { 180*0Sstevel@tonic-gate ipgpc_gather_stats = B_FALSE; /* disabled by default */ 181*0Sstevel@tonic-gate } else { 182*0Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate if ((rc = ipgpc_initialize(aid)) != 0) { 185*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \ 186*0Sstevel@tonic-gate "error %d", rc)); 187*0Sstevel@tonic-gate ipgpc_destroy(IPP_DESTROY_REF); 188*0Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 189*0Sstevel@tonic-gate nvlist_free(nvlp); 190*0Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 191*0Sstevel@tonic-gate return (rc); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate ipgpc_action_exist = B_TRUE; 194*0Sstevel@tonic-gate nvlist_free(nvlp); 195*0Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 196*0Sstevel@tonic-gate return (0); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * ipgpc_modify_action 202*0Sstevel@tonic-gate * 203*0Sstevel@tonic-gate * modify an instance of ipgpc 204*0Sstevel@tonic-gate * 205*0Sstevel@tonic-gate * nvlpp will contain the configuration type to switch off of. Use this 206*0Sstevel@tonic-gate * to determine what modification should be made. If the modification fails, 207*0Sstevel@tonic-gate * return the appropriate error. 208*0Sstevel@tonic-gate */ 209*0Sstevel@tonic-gate /* ARGSUSED */ 210*0Sstevel@tonic-gate static int 211*0Sstevel@tonic-gate ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate nvlist_t *nvlp; 214*0Sstevel@tonic-gate int rc = 0; 215*0Sstevel@tonic-gate uint8_t config_type; 216*0Sstevel@tonic-gate uint32_t stat; 217*0Sstevel@tonic-gate char *name; 218*0Sstevel@tonic-gate int32_t filter_instance; 219*0Sstevel@tonic-gate ipgpc_filter_t *filter; 220*0Sstevel@tonic-gate ipgpc_class_t *aclass; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate nvlp = *nvlpp; 223*0Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 226*0Sstevel@tonic-gate != 0) { 227*0Sstevel@tonic-gate nvlist_free(nvlp); 228*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid configuration type")); 229*0Sstevel@tonic-gate return (EINVAL); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate switch (config_type) { 233*0Sstevel@tonic-gate case IPP_SET: /* set an action parameter */ 234*0Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 235*0Sstevel@tonic-gate &stat)) != 0) { 236*0Sstevel@tonic-gate nvlist_free(nvlp); 237*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \ 238*0Sstevel@tonic-gate "parameter")); 239*0Sstevel@tonic-gate return (EINVAL); 240*0Sstevel@tonic-gate } else { 241*0Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate break; 244*0Sstevel@tonic-gate case CLASSIFIER_ADD_FILTER: /* add a filter */ 245*0Sstevel@tonic-gate filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP); 246*0Sstevel@tonic-gate if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) { 247*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid filter")); 248*0Sstevel@tonic-gate ipgpc_filter_destructor(filter); 249*0Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 250*0Sstevel@tonic-gate break; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate /* parse class name */ 253*0Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 254*0Sstevel@tonic-gate &name)) != 0) { 255*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 256*0Sstevel@tonic-gate ipgpc_filter_destructor(filter); 257*0Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 258*0Sstevel@tonic-gate break; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate rc = ipgpc_addfilter(filter, name, flags); 261*0Sstevel@tonic-gate if (rc != 0) { 262*0Sstevel@tonic-gate ipgpc_filter_destructor(filter); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 265*0Sstevel@tonic-gate break; 266*0Sstevel@tonic-gate case CLASSIFIER_ADD_CLASS: /* add a class */ 267*0Sstevel@tonic-gate aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP); 268*0Sstevel@tonic-gate if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) { 269*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid class")); 270*0Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 271*0Sstevel@tonic-gate break; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate rc = ipgpc_addclass(aclass, flags); 274*0Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 275*0Sstevel@tonic-gate break; 276*0Sstevel@tonic-gate case CLASSIFIER_REMOVE_FILTER: /* remove a filter */ 277*0Sstevel@tonic-gate /* parse filter name */ 278*0Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME, 279*0Sstevel@tonic-gate &name)) != 0) { 280*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: filtername missing")); 281*0Sstevel@tonic-gate break; 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate /* parse optional filter_instance */ 284*0Sstevel@tonic-gate if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE, 285*0Sstevel@tonic-gate &filter_instance) != 0) { 286*0Sstevel@tonic-gate filter_instance = -1; 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate rc = ipgpc_removefilter(name, filter_instance, flags); 289*0Sstevel@tonic-gate break; 290*0Sstevel@tonic-gate case CLASSIFIER_REMOVE_CLASS: /* remove a class */ 291*0Sstevel@tonic-gate /* parse class name */ 292*0Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 293*0Sstevel@tonic-gate &name)) != 0) { 294*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 295*0Sstevel@tonic-gate break; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate rc = ipgpc_removeclass(name, flags); 298*0Sstevel@tonic-gate break; 299*0Sstevel@tonic-gate case CLASSIFIER_MODIFY_FILTER: /* modify a filter */ 300*0Sstevel@tonic-gate rc = ipgpc_modifyfilter(&nvlp, flags); 301*0Sstevel@tonic-gate break; 302*0Sstevel@tonic-gate case CLASSIFIER_MODIFY_CLASS: /* modify a class */ 303*0Sstevel@tonic-gate rc = ipgpc_modifyclass(&nvlp, flags); 304*0Sstevel@tonic-gate break; 305*0Sstevel@tonic-gate default: /* invalid config type */ 306*0Sstevel@tonic-gate nvlist_free(nvlp); 307*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u", 308*0Sstevel@tonic-gate config_type)); 309*0Sstevel@tonic-gate return (EINVAL); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate nvlist_free(nvlp); /* free the list */ 312*0Sstevel@tonic-gate return (rc); /* nvlist is passed back NULL */ 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * ipgpc_destroy_action(aid, flags) 317*0Sstevel@tonic-gate * 318*0Sstevel@tonic-gate * action destructor for ipgpc 319*0Sstevel@tonic-gate * 320*0Sstevel@tonic-gate * Destroys an instance of the ipgpc action, if one exists. The 321*0Sstevel@tonic-gate * ipgpc_action_lock is taken to block out any other destroys or creates 322*0Sstevel@tonic-gate * that might be issued while the action is being destroyed 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate /* ARGSUSED */ 325*0Sstevel@tonic-gate static int 326*0Sstevel@tonic-gate ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 327*0Sstevel@tonic-gate { 328*0Sstevel@tonic-gate /* only destroy action if it exists */ 329*0Sstevel@tonic-gate if (ipgpc_action_exist == B_TRUE) { 330*0Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 331*0Sstevel@tonic-gate if (ipgpc_action_exist == B_FALSE) { 332*0Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 333*0Sstevel@tonic-gate return (EBUSY); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 336*0Sstevel@tonic-gate ipgpc_destroy(flags); 337*0Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate return (0); 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * ipgpc_info(aid, fn, arg) 344*0Sstevel@tonic-gate * 345*0Sstevel@tonic-gate * configuration quering function for ipgpc 346*0Sstevel@tonic-gate * 347*0Sstevel@tonic-gate * passes back the configuration of ipgpc through allocated nvlists 348*0Sstevel@tonic-gate * all action paramaters, classes and filters are built into nvlists 349*0Sstevel@tonic-gate * and passed to the function pointer fn with arg 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate /* ARGSUSED */ 352*0Sstevel@tonic-gate static int 353*0Sstevel@tonic-gate ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 354*0Sstevel@tonic-gate ipp_flags_t flags) 355*0Sstevel@tonic-gate { 356*0Sstevel@tonic-gate int rc; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate /* set parameters */ 359*0Sstevel@tonic-gate if ((rc = ipgpc_params_info(fn, arg)) != 0) { 360*0Sstevel@tonic-gate return (rc); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* set all classes */ 364*0Sstevel@tonic-gate if ((rc = ipgpc_classes_info(fn, arg)) != 0) { 365*0Sstevel@tonic-gate return (rc); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* set all filters */ 369*0Sstevel@tonic-gate if ((rc = ipgpc_filters_info(fn, arg)) != 0) { 370*0Sstevel@tonic-gate return (rc); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate return (0); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * ipgpc_invoke_action(aid, packet) 377*0Sstevel@tonic-gate * 378*0Sstevel@tonic-gate * packet processing function for ipgpc 379*0Sstevel@tonic-gate * 380*0Sstevel@tonic-gate * given packet the selector information is parsed and the classify 381*0Sstevel@tonic-gate * function is called with those selectors. The classify function will 382*0Sstevel@tonic-gate * return either a class or NULL, which represents a memory error and 383*0Sstevel@tonic-gate * ENOMEM is returned. If the class returned is not NULL, the class and next 384*0Sstevel@tonic-gate * action, associated with that class, are added to packet 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate /* ARGSUSED */ 387*0Sstevel@tonic-gate static int 388*0Sstevel@tonic-gate ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 389*0Sstevel@tonic-gate { 390*0Sstevel@tonic-gate ipgpc_class_t *out_class; 391*0Sstevel@tonic-gate hrtime_t start, end; 392*0Sstevel@tonic-gate mblk_t *mp = NULL; 393*0Sstevel@tonic-gate ip_priv_t *priv = NULL; 394*0Sstevel@tonic-gate ill_t *ill = NULL; 395*0Sstevel@tonic-gate ipha_t *ipha; 396*0Sstevel@tonic-gate ip_proc_t callout_pos; 397*0Sstevel@tonic-gate int af; 398*0Sstevel@tonic-gate int rc; 399*0Sstevel@tonic-gate ipgpc_packet_t pkt; 400*0Sstevel@tonic-gate uint_t ill_idx; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate /* extract packet data */ 403*0Sstevel@tonic-gate mp = ipp_packet_get_data(packet); 404*0Sstevel@tonic-gate ASSERT(mp != NULL); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate priv = (ip_priv_t *)ipp_packet_get_private(packet); 407*0Sstevel@tonic-gate ASSERT(priv != NULL); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate callout_pos = priv->proc; 410*0Sstevel@tonic-gate ill_idx = priv->ill_index; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* If we don't get an M_DATA, then return an error */ 413*0Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 414*0Sstevel@tonic-gate if ((mp->b_cont != NULL) && 415*0Sstevel@tonic-gate (mp->b_cont->b_datap->db_type == M_DATA)) { 416*0Sstevel@tonic-gate mp = mp->b_cont; /* jump over the M_CTL into M_DATA */ 417*0Sstevel@tonic-gate } else { 418*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: no data\n")); 419*0Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 420*0Sstevel@tonic-gate return (EINVAL); 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate /* 425*0Sstevel@tonic-gate * Translate the callout_pos into the direction the packet is traveling 426*0Sstevel@tonic-gate */ 427*0Sstevel@tonic-gate if (callout_pos != IPP_LOCAL_IN) { 428*0Sstevel@tonic-gate if (callout_pos & IPP_LOCAL_OUT) { 429*0Sstevel@tonic-gate callout_pos = IPP_LOCAL_OUT; 430*0Sstevel@tonic-gate } else if (callout_pos & IPP_FWD_IN) { 431*0Sstevel@tonic-gate callout_pos = IPP_FWD_IN; 432*0Sstevel@tonic-gate } else { /* IPP_FWD_OUT */ 433*0Sstevel@tonic-gate callout_pos = IPP_FWD_OUT; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* The ill_index could be 0 when called from forwarding (read) path */ 438*0Sstevel@tonic-gate if (ill_idx > 0) { 439*0Sstevel@tonic-gate ill = ill_lookup_on_ifindex(ill_idx, B_FALSE, NULL, NULL, 440*0Sstevel@tonic-gate NULL, NULL); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate /* parse the packet from the message block */ 444*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 445*0Sstevel@tonic-gate /* Determine IP Header Version */ 446*0Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) { 447*0Sstevel@tonic-gate parse_packet(&pkt, mp); 448*0Sstevel@tonic-gate af = AF_INET; 449*0Sstevel@tonic-gate } else { 450*0Sstevel@tonic-gate parse_packet6(&pkt, mp); 451*0Sstevel@tonic-gate af = AF_INET6; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate pkt.direction = callout_pos; /* set packet direction */ 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate if (ill != NULL) { 457*0Sstevel@tonic-gate pkt.if_index = ill->ill_phyint->phyint_ifindex; 458*0Sstevel@tonic-gate pkt.if_groupname_len = 459*0Sstevel@tonic-gate ill->ill_phyint->phyint_groupname_len; 460*0Sstevel@tonic-gate if (pkt.if_groupname_len > 0) { 461*0Sstevel@tonic-gate pkt.if_groupname = 462*0Sstevel@tonic-gate ill->ill_phyint->phyint_groupname; 463*0Sstevel@tonic-gate } else { 464*0Sstevel@tonic-gate pkt.if_groupname = NULL; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate /* Got the fields from the ILL, go ahead and refrele */ 467*0Sstevel@tonic-gate ill_refrele(ill); 468*0Sstevel@tonic-gate } else { 469*0Sstevel@tonic-gate /* unknown if_index and if_group */ 470*0Sstevel@tonic-gate pkt.if_index = IPGPC_UNSPECIFIED; 471*0Sstevel@tonic-gate pkt.if_groupname = NULL; 472*0Sstevel@tonic-gate pkt.if_groupname_len = 0; 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if (ipgpc_debug > 5) { 476*0Sstevel@tonic-gate /* print pkt under high debug level */ 477*0Sstevel@tonic-gate #ifdef IPGPC_DEBUG 478*0Sstevel@tonic-gate print_packet(af, &pkt); 479*0Sstevel@tonic-gate #endif 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate if (ipgpc_debug > 3) { 482*0Sstevel@tonic-gate start = gethrtime(); /* start timer */ 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* classify this packet */ 486*0Sstevel@tonic-gate out_class = ipgpc_classify(af, &pkt); 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate if (ipgpc_debug > 3) { 489*0Sstevel@tonic-gate end = gethrtime(); /* stop timer */ 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate /* ipgpc_classify will only return NULL if a memory error occured */ 493*0Sstevel@tonic-gate if (out_class == NULL) { 494*0Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 495*0Sstevel@tonic-gate return (ENOMEM); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name)); 499*0Sstevel@tonic-gate /* print time to classify(..) */ 500*0Sstevel@tonic-gate ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start))); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate if ((rc = ipp_packet_add_class(packet, out_class->class_name, 503*0Sstevel@tonic-gate out_class->next_action)) != 0) { 504*0Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 505*0Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \ 506*0Sstevel@tonic-gate "failed with error %d", rc)); 507*0Sstevel@tonic-gate return (rc); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate return (ipp_packet_next(packet, IPP_ACTION_CONT)); 510*0Sstevel@tonic-gate } 511