10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3448Sdh155122 * Common Development and Distribution License (the "License"). 6*3448Sdh155122 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3448Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/systm.h> 290Sstevel@tonic-gate #include <sys/socket.h> 300Sstevel@tonic-gate #include <netinet/in.h> 310Sstevel@tonic-gate #include <sys/modctl.h> 320Sstevel@tonic-gate #include <sys/sunddi.h> 330Sstevel@tonic-gate #include <ipp/ipp.h> 340Sstevel@tonic-gate #include <ipp/ipp_config.h> 350Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h> 360Sstevel@tonic-gate #include <inet/ip.h> 370Sstevel@tonic-gate #include <net/if.h> 380Sstevel@tonic-gate #include <inet/ip_if.h> 390Sstevel@tonic-gate #include <inet/ipp_common.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* DDI file for ipgpc ipp module */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* protects against multiple configs */ 440Sstevel@tonic-gate static kmutex_t ipgpc_config_lock; 450Sstevel@tonic-gate 460Sstevel@tonic-gate static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 470Sstevel@tonic-gate static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 480Sstevel@tonic-gate static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t); 490Sstevel@tonic-gate static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *, 500Sstevel@tonic-gate ipp_flags_t); 510Sstevel@tonic-gate static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *); 520Sstevel@tonic-gate 530Sstevel@tonic-gate ipp_ops_t ipgpc_ops = { 540Sstevel@tonic-gate IPPO_REV, 550Sstevel@tonic-gate ipgpc_create_action, /* ippo_action_create */ 560Sstevel@tonic-gate ipgpc_modify_action, /* ippo_action_modify */ 570Sstevel@tonic-gate ipgpc_destroy_action, /* ippo_action_destroy */ 580Sstevel@tonic-gate ipgpc_info, /* ippo_action_info */ 590Sstevel@tonic-gate ipgpc_invoke_action /* ippo_action_invoke */ 600Sstevel@tonic-gate }; 610Sstevel@tonic-gate 620Sstevel@tonic-gate extern struct mod_ops mod_ippops; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate * Module linkage information for the kernel. 660Sstevel@tonic-gate */ 670Sstevel@tonic-gate static struct modlipp modlipp = { 680Sstevel@tonic-gate &mod_ippops, 690Sstevel@tonic-gate "IP Generic Packet Classifier (ipgpc) module 1.0", 700Sstevel@tonic-gate &ipgpc_ops 710Sstevel@tonic-gate }; 720Sstevel@tonic-gate 730Sstevel@tonic-gate static struct modlinkage modlinkage = { 740Sstevel@tonic-gate MODREV_1, 750Sstevel@tonic-gate (void *)&modlipp, 760Sstevel@tonic-gate NULL 770Sstevel@tonic-gate }; 780Sstevel@tonic-gate 790Sstevel@tonic-gate #define __FN__ "_init" 800Sstevel@tonic-gate int 810Sstevel@tonic-gate _init( 820Sstevel@tonic-gate void) 830Sstevel@tonic-gate { 840Sstevel@tonic-gate int rc; 850Sstevel@tonic-gate 860Sstevel@tonic-gate if (ipgpc_action_exist) { 870Sstevel@tonic-gate return (EBUSY); 880Sstevel@tonic-gate } 890Sstevel@tonic-gate /* init mutexes */ 900Sstevel@tonic-gate mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL); 910Sstevel@tonic-gate mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL); 920Sstevel@tonic-gate mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL); 930Sstevel@tonic-gate mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL); 940Sstevel@tonic-gate mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL); 950Sstevel@tonic-gate 960Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) != 0) { 970Sstevel@tonic-gate /* clean up after fail */ 980Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 990Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 1000Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 1010Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1020Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate return (rc); 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate #undef __FN__ 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #define __FN__ "_fini" 1100Sstevel@tonic-gate int 1110Sstevel@tonic-gate _fini( 1120Sstevel@tonic-gate void) 1130Sstevel@tonic-gate { 1140Sstevel@tonic-gate int rc; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate if (ipgpc_action_exist) { 1170Sstevel@tonic-gate return (EBUSY); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if ((rc = mod_remove(&modlinkage)) != 0) { 1210Sstevel@tonic-gate return (rc); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate /* destroy mutexes */ 1240Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 1250Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 1260Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 1270Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1280Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1290Sstevel@tonic-gate return (rc); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate #undef __FN__ 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate #define __FN__ "_info" 1340Sstevel@tonic-gate int 1350Sstevel@tonic-gate _info( 1360Sstevel@tonic-gate struct modinfo *modinfop) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate #undef __FN__ 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate /* 1430Sstevel@tonic-gate * ipgpc_create_action(aid, nvlpp, flags) 1440Sstevel@tonic-gate * 1450Sstevel@tonic-gate * creates a single instance of ipgpc, if one does not exist. If an action 1460Sstevel@tonic-gate * instance already exists, fail with EBUSY 1470Sstevel@tonic-gate * 1480Sstevel@tonic-gate * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and 1490Sstevel@tonic-gate * determine if global stats should be collected 1500Sstevel@tonic-gate * 1510Sstevel@tonic-gate * the ipgpc_config_lock is taken to block out any other creates or destroys 1520Sstevel@tonic-gate * the are issued while the create is taking place 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate /* ARGSUSED */ 1550Sstevel@tonic-gate static int 1560Sstevel@tonic-gate ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate int rc; 1590Sstevel@tonic-gate uint32_t stat; 1600Sstevel@tonic-gate nvlist_t *nvlp; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate nvlp = *nvlpp; 1630Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* only one ipgpc action instance can be loaded at once */ 1660Sstevel@tonic-gate if (ipgpc_action_exist) { 1670Sstevel@tonic-gate nvlist_free(nvlp); 1680Sstevel@tonic-gate return (EBUSY); 1690Sstevel@tonic-gate } else { 1700Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 1710Sstevel@tonic-gate if (ipgpc_action_exist) { 1720Sstevel@tonic-gate nvlist_free(nvlp); 1730Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1740Sstevel@tonic-gate return (EBUSY); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate /* check for action param IPP_ACTION_STATS_ENABLE */ 1770Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 1780Sstevel@tonic-gate &stat)) != 0) { 1790Sstevel@tonic-gate ipgpc_gather_stats = B_FALSE; /* disabled by default */ 1800Sstevel@tonic-gate } else { 1810Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate if ((rc = ipgpc_initialize(aid)) != 0) { 1840Sstevel@tonic-gate ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \ 1850Sstevel@tonic-gate "error %d", rc)); 1860Sstevel@tonic-gate ipgpc_destroy(IPP_DESTROY_REF); 1870Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 1880Sstevel@tonic-gate nvlist_free(nvlp); 1890Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1900Sstevel@tonic-gate return (rc); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate ipgpc_action_exist = B_TRUE; 1930Sstevel@tonic-gate nvlist_free(nvlp); 1940Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1950Sstevel@tonic-gate return (0); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * ipgpc_modify_action 2010Sstevel@tonic-gate * 2020Sstevel@tonic-gate * modify an instance of ipgpc 2030Sstevel@tonic-gate * 2040Sstevel@tonic-gate * nvlpp will contain the configuration type to switch off of. Use this 2050Sstevel@tonic-gate * to determine what modification should be made. If the modification fails, 2060Sstevel@tonic-gate * return the appropriate error. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate /* ARGSUSED */ 2090Sstevel@tonic-gate static int 2100Sstevel@tonic-gate ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate nvlist_t *nvlp; 2130Sstevel@tonic-gate int rc = 0; 2140Sstevel@tonic-gate uint8_t config_type; 2150Sstevel@tonic-gate uint32_t stat; 2160Sstevel@tonic-gate char *name; 2170Sstevel@tonic-gate int32_t filter_instance; 2180Sstevel@tonic-gate ipgpc_filter_t *filter; 2190Sstevel@tonic-gate ipgpc_class_t *aclass; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate nvlp = *nvlpp; 2220Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 2250Sstevel@tonic-gate != 0) { 2260Sstevel@tonic-gate nvlist_free(nvlp); 2270Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid configuration type")); 2280Sstevel@tonic-gate return (EINVAL); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate switch (config_type) { 2320Sstevel@tonic-gate case IPP_SET: /* set an action parameter */ 2330Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 2340Sstevel@tonic-gate &stat)) != 0) { 2350Sstevel@tonic-gate nvlist_free(nvlp); 2360Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \ 2370Sstevel@tonic-gate "parameter")); 2380Sstevel@tonic-gate return (EINVAL); 2390Sstevel@tonic-gate } else { 2400Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate break; 2430Sstevel@tonic-gate case CLASSIFIER_ADD_FILTER: /* add a filter */ 2440Sstevel@tonic-gate filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP); 2450Sstevel@tonic-gate if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) { 2460Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid filter")); 2470Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2480Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2490Sstevel@tonic-gate break; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate /* parse class name */ 2520Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2530Sstevel@tonic-gate &name)) != 0) { 2540Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2550Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2560Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate rc = ipgpc_addfilter(filter, name, flags); 2600Sstevel@tonic-gate if (rc != 0) { 2610Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2640Sstevel@tonic-gate break; 2650Sstevel@tonic-gate case CLASSIFIER_ADD_CLASS: /* add a class */ 2660Sstevel@tonic-gate aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP); 2670Sstevel@tonic-gate if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) { 2680Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid class")); 2690Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate rc = ipgpc_addclass(aclass, flags); 2730Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate case CLASSIFIER_REMOVE_FILTER: /* remove a filter */ 2760Sstevel@tonic-gate /* parse filter name */ 2770Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME, 2780Sstevel@tonic-gate &name)) != 0) { 2790Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: filtername missing")); 2800Sstevel@tonic-gate break; 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate /* parse optional filter_instance */ 2830Sstevel@tonic-gate if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE, 2840Sstevel@tonic-gate &filter_instance) != 0) { 2850Sstevel@tonic-gate filter_instance = -1; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate rc = ipgpc_removefilter(name, filter_instance, flags); 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate case CLASSIFIER_REMOVE_CLASS: /* remove a class */ 2900Sstevel@tonic-gate /* parse class name */ 2910Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2920Sstevel@tonic-gate &name)) != 0) { 2930Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2940Sstevel@tonic-gate break; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate rc = ipgpc_removeclass(name, flags); 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate case CLASSIFIER_MODIFY_FILTER: /* modify a filter */ 2990Sstevel@tonic-gate rc = ipgpc_modifyfilter(&nvlp, flags); 3000Sstevel@tonic-gate break; 3010Sstevel@tonic-gate case CLASSIFIER_MODIFY_CLASS: /* modify a class */ 3020Sstevel@tonic-gate rc = ipgpc_modifyclass(&nvlp, flags); 3030Sstevel@tonic-gate break; 3040Sstevel@tonic-gate default: /* invalid config type */ 3050Sstevel@tonic-gate nvlist_free(nvlp); 3060Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u", 3070Sstevel@tonic-gate config_type)); 3080Sstevel@tonic-gate return (EINVAL); 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate nvlist_free(nvlp); /* free the list */ 3110Sstevel@tonic-gate return (rc); /* nvlist is passed back NULL */ 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * ipgpc_destroy_action(aid, flags) 3160Sstevel@tonic-gate * 3170Sstevel@tonic-gate * action destructor for ipgpc 3180Sstevel@tonic-gate * 3190Sstevel@tonic-gate * Destroys an instance of the ipgpc action, if one exists. The 3200Sstevel@tonic-gate * ipgpc_action_lock is taken to block out any other destroys or creates 3210Sstevel@tonic-gate * that might be issued while the action is being destroyed 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate /* ARGSUSED */ 3240Sstevel@tonic-gate static int 3250Sstevel@tonic-gate ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate /* only destroy action if it exists */ 3280Sstevel@tonic-gate if (ipgpc_action_exist == B_TRUE) { 3290Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 3300Sstevel@tonic-gate if (ipgpc_action_exist == B_FALSE) { 3310Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3320Sstevel@tonic-gate return (EBUSY); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 3350Sstevel@tonic-gate ipgpc_destroy(flags); 3360Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate return (0); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * ipgpc_info(aid, fn, arg) 3430Sstevel@tonic-gate * 3440Sstevel@tonic-gate * configuration quering function for ipgpc 3450Sstevel@tonic-gate * 3460Sstevel@tonic-gate * passes back the configuration of ipgpc through allocated nvlists 3470Sstevel@tonic-gate * all action paramaters, classes and filters are built into nvlists 3480Sstevel@tonic-gate * and passed to the function pointer fn with arg 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate /* ARGSUSED */ 3510Sstevel@tonic-gate static int 3520Sstevel@tonic-gate ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 3530Sstevel@tonic-gate ipp_flags_t flags) 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate int rc; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* set parameters */ 3580Sstevel@tonic-gate if ((rc = ipgpc_params_info(fn, arg)) != 0) { 3590Sstevel@tonic-gate return (rc); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* set all classes */ 3630Sstevel@tonic-gate if ((rc = ipgpc_classes_info(fn, arg)) != 0) { 3640Sstevel@tonic-gate return (rc); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* set all filters */ 3680Sstevel@tonic-gate if ((rc = ipgpc_filters_info(fn, arg)) != 0) { 3690Sstevel@tonic-gate return (rc); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate return (0); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* 3750Sstevel@tonic-gate * ipgpc_invoke_action(aid, packet) 3760Sstevel@tonic-gate * 3770Sstevel@tonic-gate * packet processing function for ipgpc 3780Sstevel@tonic-gate * 3790Sstevel@tonic-gate * given packet the selector information is parsed and the classify 3800Sstevel@tonic-gate * function is called with those selectors. The classify function will 3810Sstevel@tonic-gate * return either a class or NULL, which represents a memory error and 3820Sstevel@tonic-gate * ENOMEM is returned. If the class returned is not NULL, the class and next 3830Sstevel@tonic-gate * action, associated with that class, are added to packet 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate /* ARGSUSED */ 3860Sstevel@tonic-gate static int 3870Sstevel@tonic-gate ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate ipgpc_class_t *out_class; 3900Sstevel@tonic-gate hrtime_t start, end; 3910Sstevel@tonic-gate mblk_t *mp = NULL; 3920Sstevel@tonic-gate ip_priv_t *priv = NULL; 3930Sstevel@tonic-gate ill_t *ill = NULL; 3940Sstevel@tonic-gate ipha_t *ipha; 3950Sstevel@tonic-gate ip_proc_t callout_pos; 3960Sstevel@tonic-gate int af; 3970Sstevel@tonic-gate int rc; 3980Sstevel@tonic-gate ipgpc_packet_t pkt; 3990Sstevel@tonic-gate uint_t ill_idx; 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate /* extract packet data */ 4020Sstevel@tonic-gate mp = ipp_packet_get_data(packet); 4030Sstevel@tonic-gate ASSERT(mp != NULL); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate priv = (ip_priv_t *)ipp_packet_get_private(packet); 4060Sstevel@tonic-gate ASSERT(priv != NULL); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate callout_pos = priv->proc; 4090Sstevel@tonic-gate ill_idx = priv->ill_index; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* If we don't get an M_DATA, then return an error */ 4120Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 4130Sstevel@tonic-gate if ((mp->b_cont != NULL) && 4140Sstevel@tonic-gate (mp->b_cont->b_datap->db_type == M_DATA)) { 4150Sstevel@tonic-gate mp = mp->b_cont; /* jump over the M_CTL into M_DATA */ 4160Sstevel@tonic-gate } else { 4170Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: no data\n")); 4180Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 4190Sstevel@tonic-gate return (EINVAL); 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * Translate the callout_pos into the direction the packet is traveling 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate if (callout_pos != IPP_LOCAL_IN) { 4270Sstevel@tonic-gate if (callout_pos & IPP_LOCAL_OUT) { 4280Sstevel@tonic-gate callout_pos = IPP_LOCAL_OUT; 4290Sstevel@tonic-gate } else if (callout_pos & IPP_FWD_IN) { 4300Sstevel@tonic-gate callout_pos = IPP_FWD_IN; 4310Sstevel@tonic-gate } else { /* IPP_FWD_OUT */ 4320Sstevel@tonic-gate callout_pos = IPP_FWD_OUT; 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* The ill_index could be 0 when called from forwarding (read) path */ 4370Sstevel@tonic-gate if (ill_idx > 0) { 438*3448Sdh155122 ill = ill_lookup_on_ifindex_global_instance(ill_idx, B_FALSE, 439*3448Sdh155122 NULL, NULL, NULL, NULL); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* parse the packet from the message block */ 4430Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 4440Sstevel@tonic-gate /* Determine IP Header Version */ 4450Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) { 4460Sstevel@tonic-gate parse_packet(&pkt, mp); 4470Sstevel@tonic-gate af = AF_INET; 4480Sstevel@tonic-gate } else { 4490Sstevel@tonic-gate parse_packet6(&pkt, mp); 4500Sstevel@tonic-gate af = AF_INET6; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate pkt.direction = callout_pos; /* set packet direction */ 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (ill != NULL) { 4560Sstevel@tonic-gate pkt.if_index = ill->ill_phyint->phyint_ifindex; 4570Sstevel@tonic-gate pkt.if_groupname_len = 4580Sstevel@tonic-gate ill->ill_phyint->phyint_groupname_len; 4590Sstevel@tonic-gate if (pkt.if_groupname_len > 0) { 4600Sstevel@tonic-gate pkt.if_groupname = 4610Sstevel@tonic-gate ill->ill_phyint->phyint_groupname; 4620Sstevel@tonic-gate } else { 4630Sstevel@tonic-gate pkt.if_groupname = NULL; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate /* Got the fields from the ILL, go ahead and refrele */ 4660Sstevel@tonic-gate ill_refrele(ill); 4670Sstevel@tonic-gate } else { 4680Sstevel@tonic-gate /* unknown if_index and if_group */ 4690Sstevel@tonic-gate pkt.if_index = IPGPC_UNSPECIFIED; 4700Sstevel@tonic-gate pkt.if_groupname = NULL; 4710Sstevel@tonic-gate pkt.if_groupname_len = 0; 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate if (ipgpc_debug > 5) { 4750Sstevel@tonic-gate /* print pkt under high debug level */ 4760Sstevel@tonic-gate #ifdef IPGPC_DEBUG 4770Sstevel@tonic-gate print_packet(af, &pkt); 4780Sstevel@tonic-gate #endif 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate if (ipgpc_debug > 3) { 4810Sstevel@tonic-gate start = gethrtime(); /* start timer */ 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* classify this packet */ 4850Sstevel@tonic-gate out_class = ipgpc_classify(af, &pkt); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate if (ipgpc_debug > 3) { 4880Sstevel@tonic-gate end = gethrtime(); /* stop timer */ 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* ipgpc_classify will only return NULL if a memory error occured */ 4920Sstevel@tonic-gate if (out_class == NULL) { 4930Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 4940Sstevel@tonic-gate return (ENOMEM); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name)); 4980Sstevel@tonic-gate /* print time to classify(..) */ 4990Sstevel@tonic-gate ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start))); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate if ((rc = ipp_packet_add_class(packet, out_class->class_name, 5020Sstevel@tonic-gate out_class->next_action)) != 0) { 5030Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 5040Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \ 5050Sstevel@tonic-gate "failed with error %d", rc)); 5060Sstevel@tonic-gate return (rc); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate return (ipp_packet_next(packet, IPP_ACTION_CONT)); 5090Sstevel@tonic-gate } 510