xref: /onnv-gate/usr/src/uts/common/ipp/ipgpc/classifierddi.c (revision 0:68f95e015346)
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