17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f4b3ec61Sdh  * Common Development and Distribution License (the "License").
6f4b3ec61Sdh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/systm.h>
277c478bd9Sstevel@tonic-gate #include <sys/socket.h>
287c478bd9Sstevel@tonic-gate #include <netinet/in.h>
297c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
307c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
317c478bd9Sstevel@tonic-gate #include <ipp/ipp.h>
327c478bd9Sstevel@tonic-gate #include <ipp/ipp_config.h>
337c478bd9Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h>
347c478bd9Sstevel@tonic-gate #include <inet/ip.h>
357c478bd9Sstevel@tonic-gate #include <net/if.h>
367c478bd9Sstevel@tonic-gate #include <inet/ip_if.h>
377c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* DDI file for ipgpc ipp module */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /* protects against multiple configs  */
427c478bd9Sstevel@tonic-gate static kmutex_t ipgpc_config_lock;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
457c478bd9Sstevel@tonic-gate static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
467c478bd9Sstevel@tonic-gate static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t);
477c478bd9Sstevel@tonic-gate static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *,
487c478bd9Sstevel@tonic-gate     ipp_flags_t);
497c478bd9Sstevel@tonic-gate static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate ipp_ops_t ipgpc_ops = {
527c478bd9Sstevel@tonic-gate 	IPPO_REV,
537c478bd9Sstevel@tonic-gate 	ipgpc_create_action,	/* ippo_action_create */
547c478bd9Sstevel@tonic-gate 	ipgpc_modify_action,	/* ippo_action_modify */
557c478bd9Sstevel@tonic-gate 	ipgpc_destroy_action,	/* ippo_action_destroy */
567c478bd9Sstevel@tonic-gate 	ipgpc_info,		/* ippo_action_info */
577c478bd9Sstevel@tonic-gate 	ipgpc_invoke_action	/* ippo_action_invoke */
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate extern struct mod_ops mod_ippops;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate static struct modlipp modlipp = {
667c478bd9Sstevel@tonic-gate 	&mod_ippops,
677c478bd9Sstevel@tonic-gate 	"IP Generic Packet Classifier (ipgpc) module 1.0",
687c478bd9Sstevel@tonic-gate 	&ipgpc_ops
697c478bd9Sstevel@tonic-gate };
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
727c478bd9Sstevel@tonic-gate 	MODREV_1,
737c478bd9Sstevel@tonic-gate 	(void *)&modlipp,
747c478bd9Sstevel@tonic-gate 	NULL
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	__FN__	"_init"
787c478bd9Sstevel@tonic-gate int
_init(void)797c478bd9Sstevel@tonic-gate _init(
807c478bd9Sstevel@tonic-gate 	void)
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate 	int rc;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	if (ipgpc_action_exist) {
857c478bd9Sstevel@tonic-gate 		return (EBUSY);
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 	/* init mutexes */
887c478bd9Sstevel@tonic-gate 	mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL);
897c478bd9Sstevel@tonic-gate 	mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL);
907c478bd9Sstevel@tonic-gate 	mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL);
917c478bd9Sstevel@tonic-gate 	mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL);
927c478bd9Sstevel@tonic-gate 	mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	if ((rc = mod_install(&modlinkage)) != 0) {
957c478bd9Sstevel@tonic-gate 		/* clean up after fail */
967c478bd9Sstevel@tonic-gate 		mutex_destroy(&ipgpc_config_lock);
977c478bd9Sstevel@tonic-gate 		mutex_destroy(&ipgpc_fid_list_lock);
987c478bd9Sstevel@tonic-gate 		mutex_destroy(&ipgpc_cid_list_lock);
997c478bd9Sstevel@tonic-gate 		mutex_destroy(&ipgpc_table_list_lock);
1007c478bd9Sstevel@tonic-gate 		mutex_destroy(&ipgpc_ds_table_id.lock);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	return (rc);
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate #undef	__FN__
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate #define	__FN__	"_fini"
1087c478bd9Sstevel@tonic-gate int
_fini(void)1097c478bd9Sstevel@tonic-gate _fini(
1107c478bd9Sstevel@tonic-gate 	void)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	int rc;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	if (ipgpc_action_exist) {
1157c478bd9Sstevel@tonic-gate 		return (EBUSY);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	if ((rc = mod_remove(&modlinkage)) != 0) {
1197c478bd9Sstevel@tonic-gate 		return (rc);
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 	/* destroy mutexes */
1227c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipgpc_config_lock);
1237c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipgpc_fid_list_lock);
1247c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipgpc_cid_list_lock);
1257c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipgpc_table_list_lock);
1267c478bd9Sstevel@tonic-gate 	mutex_destroy(&ipgpc_ds_table_id.lock);
1277c478bd9Sstevel@tonic-gate 	return (rc);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate #undef	__FN__
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate #define	__FN__	"_info"
1327c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1337c478bd9Sstevel@tonic-gate _info(
1347c478bd9Sstevel@tonic-gate 	struct	modinfo *modinfop)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate #undef	__FN__
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * ipgpc_create_action(aid, nvlpp, flags)
1427c478bd9Sstevel@tonic-gate  *
1437c478bd9Sstevel@tonic-gate  * creates a single instance of ipgpc, if one does not exist.  If an action
1447c478bd9Sstevel@tonic-gate  * instance already exists, fail with EBUSY
1457c478bd9Sstevel@tonic-gate  *
1467c478bd9Sstevel@tonic-gate  * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and
1477c478bd9Sstevel@tonic-gate  * determine if global stats should be collected
1487c478bd9Sstevel@tonic-gate  *
1497c478bd9Sstevel@tonic-gate  * the ipgpc_config_lock is taken to block out any other creates or destroys
1507c478bd9Sstevel@tonic-gate  * the are issued while the create is taking place
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate /* ARGSUSED */
1537c478bd9Sstevel@tonic-gate static int
ipgpc_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)1547c478bd9Sstevel@tonic-gate ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	int rc;
1577c478bd9Sstevel@tonic-gate 	uint32_t stat;
1587c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	nvlp = *nvlpp;
1617c478bd9Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/* only one ipgpc action instance can be loaded at once */
1647c478bd9Sstevel@tonic-gate 	if (ipgpc_action_exist) {
1657c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1667c478bd9Sstevel@tonic-gate 		return (EBUSY);
1677c478bd9Sstevel@tonic-gate 	} else {
1687c478bd9Sstevel@tonic-gate 		mutex_enter(&ipgpc_config_lock);
1697c478bd9Sstevel@tonic-gate 		if (ipgpc_action_exist) {
1707c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
1717c478bd9Sstevel@tonic-gate 			mutex_exit(&ipgpc_config_lock);
1727c478bd9Sstevel@tonic-gate 			return (EBUSY);
1737c478bd9Sstevel@tonic-gate 		}
1747c478bd9Sstevel@tonic-gate 		/* check for action param IPP_ACTION_STATS_ENABLE */
1757c478bd9Sstevel@tonic-gate 		if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
1767c478bd9Sstevel@tonic-gate 		    &stat)) != 0) {
1777c478bd9Sstevel@tonic-gate 			ipgpc_gather_stats = B_FALSE; /* disabled by default */
1787c478bd9Sstevel@tonic-gate 		} else {
1797c478bd9Sstevel@tonic-gate 			ipgpc_gather_stats = (boolean_t)stat;
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 		if ((rc = ipgpc_initialize(aid)) != 0) {
1827c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \
1837c478bd9Sstevel@tonic-gate 			    "error %d", rc));
1847c478bd9Sstevel@tonic-gate 			ipgpc_destroy(IPP_DESTROY_REF);
1857c478bd9Sstevel@tonic-gate 			ipgpc_action_exist = B_FALSE;
1867c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
1877c478bd9Sstevel@tonic-gate 			mutex_exit(&ipgpc_config_lock);
1887c478bd9Sstevel@tonic-gate 			return (rc);
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 		ipgpc_action_exist = B_TRUE;
1917c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1927c478bd9Sstevel@tonic-gate 		mutex_exit(&ipgpc_config_lock);
1937c478bd9Sstevel@tonic-gate 		return (0);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * ipgpc_modify_action
1997c478bd9Sstevel@tonic-gate  *
2007c478bd9Sstevel@tonic-gate  * modify an instance of ipgpc
2017c478bd9Sstevel@tonic-gate  *
2027c478bd9Sstevel@tonic-gate  * nvlpp will contain the configuration type to switch off of.  Use this
2037c478bd9Sstevel@tonic-gate  * to determine what modification should be made.  If the modification fails,
2047c478bd9Sstevel@tonic-gate  * return the appropriate error.
2057c478bd9Sstevel@tonic-gate  */
2067c478bd9Sstevel@tonic-gate /* ARGSUSED */
2077c478bd9Sstevel@tonic-gate static int
ipgpc_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)2087c478bd9Sstevel@tonic-gate ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
2117c478bd9Sstevel@tonic-gate 	int rc = 0;
2127c478bd9Sstevel@tonic-gate 	uint8_t config_type;
2137c478bd9Sstevel@tonic-gate 	uint32_t stat;
2147c478bd9Sstevel@tonic-gate 	char *name;
2157c478bd9Sstevel@tonic-gate 	int32_t filter_instance;
2167c478bd9Sstevel@tonic-gate 	ipgpc_filter_t *filter;
2177c478bd9Sstevel@tonic-gate 	ipgpc_class_t *aclass;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	nvlp = *nvlpp;
2207c478bd9Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
2237c478bd9Sstevel@tonic-gate 	    != 0) {
2247c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
2257c478bd9Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_modify_action: invalid configuration type"));
2267c478bd9Sstevel@tonic-gate 		return (EINVAL);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	switch (config_type) {
2307c478bd9Sstevel@tonic-gate 	case IPP_SET:		/* set an action parameter */
2317c478bd9Sstevel@tonic-gate 		if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
2327c478bd9Sstevel@tonic-gate 		    &stat)) != 0) {
2337c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
2347c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \
2357c478bd9Sstevel@tonic-gate 			    "parameter"));
2367c478bd9Sstevel@tonic-gate 			return (EINVAL);
2377c478bd9Sstevel@tonic-gate 		} else {
2387c478bd9Sstevel@tonic-gate 			ipgpc_gather_stats = (boolean_t)stat;
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 		break;
2417c478bd9Sstevel@tonic-gate 	case CLASSIFIER_ADD_FILTER: /* add a filter */
2427c478bd9Sstevel@tonic-gate 		filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP);
2437c478bd9Sstevel@tonic-gate 		if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) {
2447c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: invalid filter"));
2457c478bd9Sstevel@tonic-gate 			ipgpc_filter_destructor(filter);
2467c478bd9Sstevel@tonic-gate 			kmem_free(filter, sizeof (ipgpc_filter_t));
2477c478bd9Sstevel@tonic-gate 			break;
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		/* parse class name */
2507c478bd9Sstevel@tonic-gate 		if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME,
2517c478bd9Sstevel@tonic-gate 		    &name)) != 0) {
2527c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: class name missing"));
2537c478bd9Sstevel@tonic-gate 			ipgpc_filter_destructor(filter);
2547c478bd9Sstevel@tonic-gate 			kmem_free(filter, sizeof (ipgpc_filter_t));
2557c478bd9Sstevel@tonic-gate 			break;
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		rc = ipgpc_addfilter(filter, name, flags);
2587c478bd9Sstevel@tonic-gate 		if (rc != 0) {
2597c478bd9Sstevel@tonic-gate 			ipgpc_filter_destructor(filter);
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 		kmem_free(filter, sizeof (ipgpc_filter_t));
2627c478bd9Sstevel@tonic-gate 		break;
2637c478bd9Sstevel@tonic-gate 	case CLASSIFIER_ADD_CLASS: /* add a class */
2647c478bd9Sstevel@tonic-gate 		aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP);
2657c478bd9Sstevel@tonic-gate 		if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) {
2667c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: invalid class"));
2677c478bd9Sstevel@tonic-gate 			kmem_free(aclass, sizeof (ipgpc_class_t));
2687c478bd9Sstevel@tonic-gate 			break;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 		rc = ipgpc_addclass(aclass, flags);
2717c478bd9Sstevel@tonic-gate 		kmem_free(aclass, sizeof (ipgpc_class_t));
2727c478bd9Sstevel@tonic-gate 		break;
2737c478bd9Sstevel@tonic-gate 	case CLASSIFIER_REMOVE_FILTER: /* remove a filter */
2747c478bd9Sstevel@tonic-gate 		/* parse filter name */
2757c478bd9Sstevel@tonic-gate 		if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME,
2767c478bd9Sstevel@tonic-gate 		    &name)) != 0) {
2777c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: filtername missing"));
2787c478bd9Sstevel@tonic-gate 			break;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		/* parse optional filter_instance */
2817c478bd9Sstevel@tonic-gate 		if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE,
2827c478bd9Sstevel@tonic-gate 		    &filter_instance) != 0) {
2837c478bd9Sstevel@tonic-gate 			filter_instance = -1;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 		rc = ipgpc_removefilter(name, filter_instance, flags);
2867c478bd9Sstevel@tonic-gate 		break;
2877c478bd9Sstevel@tonic-gate 	case CLASSIFIER_REMOVE_CLASS: /* remove a class */
2887c478bd9Sstevel@tonic-gate 		/* parse class name */
2897c478bd9Sstevel@tonic-gate 		if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME,
2907c478bd9Sstevel@tonic-gate 		    &name)) != 0) {
2917c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_modify_action: class name missing"));
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 		rc = ipgpc_removeclass(name, flags);
2957c478bd9Sstevel@tonic-gate 		break;
2967c478bd9Sstevel@tonic-gate 	case CLASSIFIER_MODIFY_FILTER: /* modify a filter */
2977c478bd9Sstevel@tonic-gate 		rc = ipgpc_modifyfilter(&nvlp, flags);
2987c478bd9Sstevel@tonic-gate 		break;
2997c478bd9Sstevel@tonic-gate 	case CLASSIFIER_MODIFY_CLASS: /* modify a class */
3007c478bd9Sstevel@tonic-gate 		rc = ipgpc_modifyclass(&nvlp, flags);
3017c478bd9Sstevel@tonic-gate 		break;
3027c478bd9Sstevel@tonic-gate 	default:		/* invalid config type */
3037c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
3047c478bd9Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u",
3057c478bd9Sstevel@tonic-gate 		    config_type));
3067c478bd9Sstevel@tonic-gate 		return (EINVAL);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 	nvlist_free(nvlp);	/* free the list */
3097c478bd9Sstevel@tonic-gate 	return (rc);		/* nvlist is passed back NULL */
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * ipgpc_destroy_action(aid, flags)
3147c478bd9Sstevel@tonic-gate  *
3157c478bd9Sstevel@tonic-gate  * action destructor for ipgpc
3167c478bd9Sstevel@tonic-gate  *
3177c478bd9Sstevel@tonic-gate  * Destroys an instance of the ipgpc action, if one exists. The
3187c478bd9Sstevel@tonic-gate  * ipgpc_action_lock is taken to block out any other destroys or creates
3197c478bd9Sstevel@tonic-gate  * that might be issued while the action is being destroyed
3207c478bd9Sstevel@tonic-gate  */
3217c478bd9Sstevel@tonic-gate /* ARGSUSED */
3227c478bd9Sstevel@tonic-gate static int
ipgpc_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)3237c478bd9Sstevel@tonic-gate ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	/* only destroy action if it exists */
3267c478bd9Sstevel@tonic-gate 	if (ipgpc_action_exist == B_TRUE) {
3277c478bd9Sstevel@tonic-gate 		mutex_enter(&ipgpc_config_lock);
3287c478bd9Sstevel@tonic-gate 		if (ipgpc_action_exist == B_FALSE) {
3297c478bd9Sstevel@tonic-gate 			mutex_exit(&ipgpc_config_lock);
3307c478bd9Sstevel@tonic-gate 			return (EBUSY);
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 		ipgpc_action_exist = B_FALSE;
3337c478bd9Sstevel@tonic-gate 		ipgpc_destroy(flags);
3347c478bd9Sstevel@tonic-gate 		mutex_exit(&ipgpc_config_lock);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	return (0);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * ipgpc_info(aid, fn, arg)
3417c478bd9Sstevel@tonic-gate  *
3427c478bd9Sstevel@tonic-gate  * configuration quering function for ipgpc
3437c478bd9Sstevel@tonic-gate  *
3447c478bd9Sstevel@tonic-gate  * passes back the configuration of ipgpc through allocated nvlists
3457c478bd9Sstevel@tonic-gate  * all action paramaters, classes and filters are built into nvlists
3467c478bd9Sstevel@tonic-gate  * and passed to the function pointer fn with arg
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate /* ARGSUSED */
3497c478bd9Sstevel@tonic-gate static int
ipgpc_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)3507c478bd9Sstevel@tonic-gate ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
3517c478bd9Sstevel@tonic-gate     ipp_flags_t flags)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	int rc;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* set parameters */
3567c478bd9Sstevel@tonic-gate 	if ((rc = ipgpc_params_info(fn, arg)) != 0) {
3577c478bd9Sstevel@tonic-gate 		return (rc);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* set all classes */
3617c478bd9Sstevel@tonic-gate 	if ((rc = ipgpc_classes_info(fn, arg)) != 0) {
3627c478bd9Sstevel@tonic-gate 		return (rc);
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/* set all filters */
3667c478bd9Sstevel@tonic-gate 	if ((rc = ipgpc_filters_info(fn, arg)) != 0) {
3677c478bd9Sstevel@tonic-gate 		return (rc);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 	return (0);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate  * ipgpc_invoke_action(aid, packet)
3747c478bd9Sstevel@tonic-gate  *
3757c478bd9Sstevel@tonic-gate  * packet processing function for ipgpc
3767c478bd9Sstevel@tonic-gate  *
3777c478bd9Sstevel@tonic-gate  * given packet the selector information is parsed and the classify
3787c478bd9Sstevel@tonic-gate  * function is called with those selectors.  The classify function will
3797c478bd9Sstevel@tonic-gate  * return either a class or NULL, which represents a memory error and
3807c478bd9Sstevel@tonic-gate  * ENOMEM is returned.  If the class returned is not NULL, the class and next
3817c478bd9Sstevel@tonic-gate  * action, associated with that class, are added to packet
3827c478bd9Sstevel@tonic-gate  */
3837c478bd9Sstevel@tonic-gate /* ARGSUSED */
3847c478bd9Sstevel@tonic-gate static int
ipgpc_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)3857c478bd9Sstevel@tonic-gate ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
3867c478bd9Sstevel@tonic-gate {
3877c478bd9Sstevel@tonic-gate 	ipgpc_class_t *out_class;
3887c478bd9Sstevel@tonic-gate 	hrtime_t start, end;
3897c478bd9Sstevel@tonic-gate 	mblk_t *mp = NULL;
3907c478bd9Sstevel@tonic-gate 	ip_priv_t *priv = NULL;
3917c478bd9Sstevel@tonic-gate 	ill_t *ill = NULL;
3927c478bd9Sstevel@tonic-gate 	ipha_t *ipha;
3937c478bd9Sstevel@tonic-gate 	ip_proc_t callout_pos;
3947c478bd9Sstevel@tonic-gate 	int af;
3957c478bd9Sstevel@tonic-gate 	int rc;
3967c478bd9Sstevel@tonic-gate 	ipgpc_packet_t pkt;
3977c478bd9Sstevel@tonic-gate 	uint_t ill_idx;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/* extract packet data */
4007c478bd9Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
4017c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	priv = (ip_priv_t *)ipp_packet_get_private(packet);
4047c478bd9Sstevel@tonic-gate 	ASSERT(priv != NULL);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	callout_pos = priv->proc;
4077c478bd9Sstevel@tonic-gate 	ill_idx = priv->ill_index;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* If we don't get an M_DATA, then return an error */
4107c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_DATA) {
4117c478bd9Sstevel@tonic-gate 		if ((mp->b_cont != NULL) &&
4127c478bd9Sstevel@tonic-gate 		    (mp->b_cont->b_datap->db_type == M_DATA)) {
4137c478bd9Sstevel@tonic-gate 			mp = mp->b_cont; /* jump over the M_CTL into M_DATA */
4147c478bd9Sstevel@tonic-gate 		} else {
4157c478bd9Sstevel@tonic-gate 			ipgpc0dbg(("ipgpc_invoke_action: no data\n"));
416*1a5e258fSJosef 'Jeff' Sipek 			atomic_inc_64(&ipgpc_epackets);
4177c478bd9Sstevel@tonic-gate 			return (EINVAL);
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
4227c478bd9Sstevel@tonic-gate 	 * Translate the callout_pos into the direction the packet is traveling
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	if (callout_pos != IPP_LOCAL_IN) {
4257c478bd9Sstevel@tonic-gate 		if (callout_pos & IPP_LOCAL_OUT) {
4267c478bd9Sstevel@tonic-gate 			callout_pos = IPP_LOCAL_OUT;
4277c478bd9Sstevel@tonic-gate 		} else if (callout_pos & IPP_FWD_IN) {
4287c478bd9Sstevel@tonic-gate 			callout_pos = IPP_FWD_IN;
4297c478bd9Sstevel@tonic-gate 		} else {	/* IPP_FWD_OUT */
4307c478bd9Sstevel@tonic-gate 			callout_pos = IPP_FWD_OUT;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/* parse the packet from the message block */
4357c478bd9Sstevel@tonic-gate 	ipha = (ipha_t *)mp->b_rptr;
4367c478bd9Sstevel@tonic-gate 	/* Determine IP Header Version */
4377c478bd9Sstevel@tonic-gate 	if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) {
4387c478bd9Sstevel@tonic-gate 		parse_packet(&pkt, mp);
4397c478bd9Sstevel@tonic-gate 		af = AF_INET;
4407c478bd9Sstevel@tonic-gate 	} else {
4417c478bd9Sstevel@tonic-gate 		parse_packet6(&pkt, mp);
4427c478bd9Sstevel@tonic-gate 		af = AF_INET6;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	pkt.direction = callout_pos; /* set packet direction */
4467c478bd9Sstevel@tonic-gate 
447e11c3f44Smeem 	/* The ill_index could be 0 when called from forwarding (read) path */
448bd670b35SErik Nordmark 	if (ill_idx > 0)
449bd670b35SErik Nordmark 		ill = ill_lookup_on_ifindex_global_instance(ill_idx, B_FALSE);
450bd670b35SErik Nordmark 
4517c478bd9Sstevel@tonic-gate 	if (ill != NULL) {
452e11c3f44Smeem 		/*
453e11c3f44Smeem 		 * Since all IPP actions in an IPMP group are performed
454e11c3f44Smeem 		 * relative to the IPMP group interface, if this is an
455e11c3f44Smeem 		 * underlying interface in an IPMP group, use the IPMP
456e11c3f44Smeem 		 * group interface's index.
457e11c3f44Smeem 		 */
458e11c3f44Smeem 		if (IS_UNDER_IPMP(ill))
459e11c3f44Smeem 			pkt.if_index = ipmp_ill_get_ipmp_ifindex(ill);
460e11c3f44Smeem 		else
461e11c3f44Smeem 			pkt.if_index = ill->ill_phyint->phyint_ifindex;
462e11c3f44Smeem 		/* Got the field from the ILL, go ahead and refrele */
4637c478bd9Sstevel@tonic-gate 		ill_refrele(ill);
4647c478bd9Sstevel@tonic-gate 	} else {
465e11c3f44Smeem 		/* unknown if_index */
4667c478bd9Sstevel@tonic-gate 		pkt.if_index = IPGPC_UNSPECIFIED;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (ipgpc_debug > 5) {
4707c478bd9Sstevel@tonic-gate 		/* print pkt under high debug level */
4717c478bd9Sstevel@tonic-gate #ifdef	IPGPC_DEBUG
4727c478bd9Sstevel@tonic-gate 		print_packet(af, &pkt);
4737c478bd9Sstevel@tonic-gate #endif
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	if (ipgpc_debug > 3) {
4767c478bd9Sstevel@tonic-gate 		start = gethrtime(); /* start timer */
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* classify this packet */
4807c478bd9Sstevel@tonic-gate 	out_class = ipgpc_classify(af, &pkt);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if (ipgpc_debug > 3) {
4837c478bd9Sstevel@tonic-gate 		end = gethrtime(); /* stop timer */
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/* ipgpc_classify will only return NULL if a memory error occured */
4877c478bd9Sstevel@tonic-gate 	if (out_class == NULL) {
488*1a5e258fSJosef 'Jeff' Sipek 		atomic_inc_64(&ipgpc_epackets);
4897c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name));
4937c478bd9Sstevel@tonic-gate 	/* print time to classify(..) */
4947c478bd9Sstevel@tonic-gate 	ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start)));
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	if ((rc = ipp_packet_add_class(packet, out_class->class_name,
4977c478bd9Sstevel@tonic-gate 	    out_class->next_action)) != 0) {
498*1a5e258fSJosef 'Jeff' Sipek 		atomic_inc_64(&ipgpc_epackets);
4997c478bd9Sstevel@tonic-gate 		ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \
5007c478bd9Sstevel@tonic-gate 		    "failed with error %d", rc));
5017c478bd9Sstevel@tonic-gate 		return (rc);
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 	return (ipp_packet_next(packet, IPP_ACTION_CONT));
5047c478bd9Sstevel@tonic-gate }
505