xref: /titanic_51/usr/src/uts/common/inet/ipf/solaris.c (revision 94bdecd9e84ae1042607002db3e64a6849da5874)
1ab25eeb5Syz155240 /*
2ab25eeb5Syz155240  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3ab25eeb5Syz155240  *
4ab25eeb5Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5ab25eeb5Syz155240  *
614d3298eSAlexandr Nedvedicky  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
7ab25eeb5Syz155240  * Use is subject to license terms.
8*94bdecd9SRob Gulewich  *
9*94bdecd9SRob Gulewich  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
10*94bdecd9SRob Gulewich  */
11*94bdecd9SRob Gulewich 
12*94bdecd9SRob Gulewich /*
13*94bdecd9SRob Gulewich  * ipfilter kernel module mutexes and locking:
14*94bdecd9SRob Gulewich  *
15*94bdecd9SRob Gulewich  * Enabling ipfilter creates a per-netstack ipf_stack_t object that is
16*94bdecd9SRob Gulewich  * stored in the ipf_stacks list, which is protected by ipf_stack_lock.
17*94bdecd9SRob Gulewich  * ipf_stack_t objects are accessed in three contexts:
18*94bdecd9SRob Gulewich  *
19*94bdecd9SRob Gulewich  * 1) administering that filter (eg: ioctls handled with iplioctl())
20*94bdecd9SRob Gulewich  * 2) reading log data (eg: iplread() / iplwrite())
21*94bdecd9SRob Gulewich  * 3) filtering packets (eg: ipf_hook4_* and ipf_hook6_* pfhooks
22*94bdecd9SRob Gulewich  *    functions)
23*94bdecd9SRob Gulewich  *
24*94bdecd9SRob Gulewich  * Each ipf_stack_t has a RW lock, ifs_ipf_global, protecting access to the
25*94bdecd9SRob Gulewich  * whole structure. The structure also has locks protecting the various
26*94bdecd9SRob Gulewich  * data structures used for filtering. The following guidelines should be
27*94bdecd9SRob Gulewich  * followed for ipf_stack_t locks:
28*94bdecd9SRob Gulewich  *
29*94bdecd9SRob Gulewich  * - ipf_stack_lock must be held when accessing the ipf_stacks list
30*94bdecd9SRob Gulewich  * - ipf_stack_lock should be held before acquiring ifs_ipf_global for
31*94bdecd9SRob Gulewich  *   a stack (the exception to this is ipf_stack_destroy(), which removes
32*94bdecd9SRob Gulewich  *   the ipf_stack_t from the list, then drops ipf_stack_lock before
33*94bdecd9SRob Gulewich  *   acquiring ifs_ipf_global)
34*94bdecd9SRob Gulewich  * - ifs_ipf_global must be held when accessing an ipf_stack_t in that list:
35*94bdecd9SRob Gulewich  *   - The write lock is held only during stack creation / destruction
36*94bdecd9SRob Gulewich  *   - The read lock should be held for all other accesses
37*94bdecd9SRob Gulewich  * - To alter the filtering data in the administrative context, one must:
38*94bdecd9SRob Gulewich  *   - acquire the read lock for ifs_ipf_global
39*94bdecd9SRob Gulewich  *   - then acquire the write lock for the data in question
40*94bdecd9SRob Gulewich  * - In the filtering path, the read lock needs to be held for each type of
41*94bdecd9SRob Gulewich  *   filtering data used
42*94bdecd9SRob Gulewich  * - ifs_ipf_global does not need to be held in the filtering path:
43*94bdecd9SRob Gulewich  *   - The filtering hooks don't need to modify the stack itself
44*94bdecd9SRob Gulewich  *   - The ipf_stack_t will not be destroyed until the hooks are unregistered.
45*94bdecd9SRob Gulewich  *     This requires a write lock on the hook, ensuring that no active hooks
46*94bdecd9SRob Gulewich  *     (eg: the filtering path) are running, and that the hooks won't be run
47*94bdecd9SRob Gulewich  *     afterward.
48*94bdecd9SRob Gulewich  *
49*94bdecd9SRob Gulewich  * Note that there is a deadlock possible when calling net_hook_register()
50*94bdecd9SRob Gulewich  * or net_hook_unregister() with ifs_ipf_global held: see the comments in
51*94bdecd9SRob Gulewich  * iplattach() and ipldetach() for details.
52ab25eeb5Syz155240  */
53ab25eeb5Syz155240 
54ab25eeb5Syz155240 #include <sys/systm.h>
55ab25eeb5Syz155240 #include <sys/types.h>
56ab25eeb5Syz155240 #include <sys/param.h>
57ab25eeb5Syz155240 #include <sys/errno.h>
58ab25eeb5Syz155240 #include <sys/uio.h>
59ab25eeb5Syz155240 #include <sys/buf.h>
60ab25eeb5Syz155240 #include <sys/modctl.h>
61ab25eeb5Syz155240 #include <sys/open.h>
62ab25eeb5Syz155240 #include <sys/kmem.h>
63ab25eeb5Syz155240 #include <sys/conf.h>
64ab25eeb5Syz155240 #include <sys/cmn_err.h>
65ab25eeb5Syz155240 #include <sys/stat.h>
66ab25eeb5Syz155240 #include <sys/cred.h>
67ab25eeb5Syz155240 #include <sys/dditypes.h>
68ab25eeb5Syz155240 #include <sys/poll.h>
69ab25eeb5Syz155240 #include <sys/autoconf.h>
70ab25eeb5Syz155240 #include <sys/byteorder.h>
71ab25eeb5Syz155240 #include <sys/socket.h>
72ab25eeb5Syz155240 #include <sys/dlpi.h>
73ab25eeb5Syz155240 #include <sys/stropts.h>
74ab25eeb5Syz155240 #include <sys/kstat.h>
75ab25eeb5Syz155240 #include <sys/sockio.h>
76381a2a9aSdr146992 #include <sys/neti.h>
77381a2a9aSdr146992 #include <sys/hook.h>
78ab25eeb5Syz155240 #include <net/if.h>
79ab25eeb5Syz155240 #if SOLARIS2 >= 6
80ab25eeb5Syz155240 #include <net/if_types.h>
81ab25eeb5Syz155240 #endif
82ab25eeb5Syz155240 #include <net/af.h>
83ab25eeb5Syz155240 #include <net/route.h>
84ab25eeb5Syz155240 #include <netinet/in.h>
85ab25eeb5Syz155240 #include <netinet/in_systm.h>
86ab25eeb5Syz155240 #include <netinet/if_ether.h>
87ab25eeb5Syz155240 #include <netinet/ip.h>
88ab25eeb5Syz155240 #include <netinet/ip_var.h>
89ab25eeb5Syz155240 #include <netinet/tcp.h>
90ab25eeb5Syz155240 #include <netinet/udp.h>
91ab25eeb5Syz155240 #include <netinet/tcpip.h>
92ab25eeb5Syz155240 #include <netinet/ip_icmp.h>
93ab25eeb5Syz155240 #include <sys/ddi.h>
94ab25eeb5Syz155240 #include <sys/sunddi.h>
95ab25eeb5Syz155240 #include "netinet/ip_compat.h"
96ab25eeb5Syz155240 #include "netinet/ipl.h"
97ab25eeb5Syz155240 #include "netinet/ip_fil.h"
98ab25eeb5Syz155240 #include "netinet/ip_nat.h"
99ab25eeb5Syz155240 #include "netinet/ip_frag.h"
100ab25eeb5Syz155240 #include "netinet/ip_auth.h"
101ab25eeb5Syz155240 #include "netinet/ip_state.h"
102f4b3ec61Sdh155122 #include "netinet/ipf_stack.h"
103ab25eeb5Syz155240 
104ab25eeb5Syz155240 extern	int	iplwrite __P((dev_t, struct uio *, cred_t *));
105ab25eeb5Syz155240 
106ab25eeb5Syz155240 static	int	ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
107ab25eeb5Syz155240 		    void *, void **));
108ab25eeb5Syz155240 #if SOLARIS2 < 10
109ab25eeb5Syz155240 static	int	ipf_identify __P((dev_info_t *));
110ab25eeb5Syz155240 #endif
111ab25eeb5Syz155240 static	int	ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
112ab25eeb5Syz155240 static	int	ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
1137ddc9b1aSDarren Reed static	void	*ipf_stack_create __P((const netid_t));
1147ddc9b1aSDarren Reed static	void	ipf_stack_destroy __P((const netid_t, void *));
1158ad74188SDarren Reed static	void	ipf_stack_shutdown __P((const netid_t, void *));
116f4b3ec61Sdh155122 static	int	ipf_property_g_update __P((dev_info_t *));
117ab25eeb5Syz155240 static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
118ab25eeb5Syz155240 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
119ab25eeb5Syz155240 				    IPLOOKUP_NAME, NULL };
120*94bdecd9SRob Gulewich extern void 	*ipf_state;	/* DDI state */
121*94bdecd9SRob Gulewich extern vmem_t	*ipf_minor;	/* minor number arena */
122ab25eeb5Syz155240 
123ab25eeb5Syz155240 static struct cb_ops ipf_cb_ops = {
124ab25eeb5Syz155240 	iplopen,
125ab25eeb5Syz155240 	iplclose,
126ab25eeb5Syz155240 	nodev,		/* strategy */
127ab25eeb5Syz155240 	nodev,		/* print */
128ab25eeb5Syz155240 	nodev,		/* dump */
129ab25eeb5Syz155240 	iplread,
130ab25eeb5Syz155240 	iplwrite,	/* write */
131ab25eeb5Syz155240 	iplioctl,	/* ioctl */
132ab25eeb5Syz155240 	nodev,		/* devmap */
133ab25eeb5Syz155240 	nodev,		/* mmap */
134ab25eeb5Syz155240 	nodev,		/* segmap */
135ab25eeb5Syz155240 	nochpoll,	/* poll */
136ab25eeb5Syz155240 	ddi_prop_op,
137ab25eeb5Syz155240 	NULL,
138ab25eeb5Syz155240 	D_MTSAFE,
139ab25eeb5Syz155240 #if SOLARIS2 > 4
140ab25eeb5Syz155240 	CB_REV,
141ab25eeb5Syz155240 	nodev,		/* aread */
142ab25eeb5Syz155240 	nodev,		/* awrite */
143ab25eeb5Syz155240 #endif
144ab25eeb5Syz155240 };
145ab25eeb5Syz155240 
146ab25eeb5Syz155240 static struct dev_ops ipf_ops = {
147ab25eeb5Syz155240 	DEVO_REV,
148ab25eeb5Syz155240 	0,
149ab25eeb5Syz155240 	ipf_getinfo,
150ab25eeb5Syz155240 #if SOLARIS2 >= 10
151ab25eeb5Syz155240 	nulldev,
152ab25eeb5Syz155240 #else
153ab25eeb5Syz155240 	ipf_identify,
154ab25eeb5Syz155240 #endif
155ab25eeb5Syz155240 	nulldev,
156ab25eeb5Syz155240 	ipf_attach,
157ab25eeb5Syz155240 	ipf_detach,
158ab25eeb5Syz155240 	nodev,		/* reset */
159ab25eeb5Syz155240 	&ipf_cb_ops,
16019397407SSherry Moore 	(struct bus_ops *)0,
16119397407SSherry Moore 	NULL,
16219397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
163ab25eeb5Syz155240 };
164ab25eeb5Syz155240 
1657ddc9b1aSDarren Reed 
1667ddc9b1aSDarren Reed static net_instance_t *ipfncb = NULL;
1677ddc9b1aSDarren Reed static ipf_stack_t *ipf_stacks = NULL;
1687ddc9b1aSDarren Reed static kmutex_t ipf_stack_lock;
169ab25eeb5Syz155240 extern struct mod_ops mod_driverops;
170ab25eeb5Syz155240 static struct modldrv iplmod = {
171ab25eeb5Syz155240 	&mod_driverops, IPL_VERSION, &ipf_ops };
172ab25eeb5Syz155240 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
173ab25eeb5Syz155240 
174ab25eeb5Syz155240 #if SOLARIS2 >= 6
175ab25eeb5Syz155240 static	size_t	hdrsizes[57][2] = {
176ab25eeb5Syz155240 	{ 0, 0 },
177ab25eeb5Syz155240 	{ IFT_OTHER, 0 },
178ab25eeb5Syz155240 	{ IFT_1822, 0 },
179ab25eeb5Syz155240 	{ IFT_HDH1822, 0 },
180ab25eeb5Syz155240 	{ IFT_X25DDN, 0 },
181ab25eeb5Syz155240 	{ IFT_X25, 0 },
182ab25eeb5Syz155240 	{ IFT_ETHER, 14 },
183ab25eeb5Syz155240 	{ IFT_ISO88023, 0 },
184ab25eeb5Syz155240 	{ IFT_ISO88024, 0 },
185ab25eeb5Syz155240 	{ IFT_ISO88025, 0 },
186ab25eeb5Syz155240 	{ IFT_ISO88026, 0 },
187ab25eeb5Syz155240 	{ IFT_STARLAN, 0 },
188ab25eeb5Syz155240 	{ IFT_P10, 0 },
189ab25eeb5Syz155240 	{ IFT_P80, 0 },
190ab25eeb5Syz155240 	{ IFT_HY, 0 },
191ab25eeb5Syz155240 	{ IFT_FDDI, 24 },
192ab25eeb5Syz155240 	{ IFT_LAPB, 0 },
193ab25eeb5Syz155240 	{ IFT_SDLC, 0 },
194ab25eeb5Syz155240 	{ IFT_T1, 0 },
195ab25eeb5Syz155240 	{ IFT_CEPT, 0 },
196ab25eeb5Syz155240 	{ IFT_ISDNBASIC, 0 },
197ab25eeb5Syz155240 	{ IFT_ISDNPRIMARY, 0 },
198ab25eeb5Syz155240 	{ IFT_PTPSERIAL, 0 },
199ab25eeb5Syz155240 	{ IFT_PPP, 0 },
200ab25eeb5Syz155240 	{ IFT_LOOP, 0 },
201ab25eeb5Syz155240 	{ IFT_EON, 0 },
202ab25eeb5Syz155240 	{ IFT_XETHER, 0 },
203ab25eeb5Syz155240 	{ IFT_NSIP, 0 },
204ab25eeb5Syz155240 	{ IFT_SLIP, 0 },
205ab25eeb5Syz155240 	{ IFT_ULTRA, 0 },
206ab25eeb5Syz155240 	{ IFT_DS3, 0 },
207ab25eeb5Syz155240 	{ IFT_SIP, 0 },
208ab25eeb5Syz155240 	{ IFT_FRELAY, 0 },
209ab25eeb5Syz155240 	{ IFT_RS232, 0 },
210ab25eeb5Syz155240 	{ IFT_PARA, 0 },
211ab25eeb5Syz155240 	{ IFT_ARCNET, 0 },
212ab25eeb5Syz155240 	{ IFT_ARCNETPLUS, 0 },
213ab25eeb5Syz155240 	{ IFT_ATM, 0 },
214ab25eeb5Syz155240 	{ IFT_MIOX25, 0 },
215ab25eeb5Syz155240 	{ IFT_SONET, 0 },
216ab25eeb5Syz155240 	{ IFT_X25PLE, 0 },
217ab25eeb5Syz155240 	{ IFT_ISO88022LLC, 0 },
218ab25eeb5Syz155240 	{ IFT_LOCALTALK, 0 },
219ab25eeb5Syz155240 	{ IFT_SMDSDXI, 0 },
220ab25eeb5Syz155240 	{ IFT_FRELAYDCE, 0 },
221ab25eeb5Syz155240 	{ IFT_V35, 0 },
222ab25eeb5Syz155240 	{ IFT_HSSI, 0 },
223ab25eeb5Syz155240 	{ IFT_HIPPI, 0 },
224ab25eeb5Syz155240 	{ IFT_MODEM, 0 },
225ab25eeb5Syz155240 	{ IFT_AAL5, 0 },
226ab25eeb5Syz155240 	{ IFT_SONETPATH, 0 },
227ab25eeb5Syz155240 	{ IFT_SONETVT, 0 },
228ab25eeb5Syz155240 	{ IFT_SMDSICIP, 0 },
229ab25eeb5Syz155240 	{ IFT_PROPVIRTUAL, 0 },
230ab25eeb5Syz155240 	{ IFT_PROPMUX, 0 },
231ab25eeb5Syz155240 };
232ab25eeb5Syz155240 #endif /* SOLARIS2 >= 6 */
233ab25eeb5Syz155240 
234f4b3ec61Sdh155122 dev_info_t *ipf_dev_info = NULL;
235ab25eeb5Syz155240 
236ab25eeb5Syz155240 static const filter_kstats_t ipf_kstat_tmp = {
237ab25eeb5Syz155240 	{ "pass",			KSTAT_DATA_ULONG },
238ab25eeb5Syz155240 	{ "block",			KSTAT_DATA_ULONG },
239ab25eeb5Syz155240 	{ "nomatch",			KSTAT_DATA_ULONG },
240ab25eeb5Syz155240 	{ "short",			KSTAT_DATA_ULONG },
241ab25eeb5Syz155240 	{ "pass, logged",		KSTAT_DATA_ULONG },
242ab25eeb5Syz155240 	{ "block, logged",		KSTAT_DATA_ULONG },
243ab25eeb5Syz155240 	{ "nomatch, logged",		KSTAT_DATA_ULONG },
244ab25eeb5Syz155240 	{ "logged",			KSTAT_DATA_ULONG },
245ab25eeb5Syz155240 	{ "skip",			KSTAT_DATA_ULONG },
246ab25eeb5Syz155240 	{ "return sent",		KSTAT_DATA_ULONG },
247ab25eeb5Syz155240 	{ "acct",			KSTAT_DATA_ULONG },
248ab25eeb5Syz155240 	{ "bad frag state alloc",	KSTAT_DATA_ULONG },
249ab25eeb5Syz155240 	{ "new frag state kept",	KSTAT_DATA_ULONG },
250ab25eeb5Syz155240 	{ "new frag state compl. pkt",	KSTAT_DATA_ULONG },
251ab25eeb5Syz155240 	{ "bad pkt state alloc",	KSTAT_DATA_ULONG },
252ab25eeb5Syz155240 	{ "new pkt kept state",		KSTAT_DATA_ULONG },
253ab25eeb5Syz155240 	{ "cachehit",			KSTAT_DATA_ULONG },
254ab25eeb5Syz155240 	{ "tcp cksum bad",		KSTAT_DATA_ULONG },
255ab25eeb5Syz155240 	{{ "pullup ok",			KSTAT_DATA_ULONG },
256ab25eeb5Syz155240 	{ "pullup nok",			KSTAT_DATA_ULONG }},
257ab25eeb5Syz155240 	{ "src != route",		KSTAT_DATA_ULONG },
258ab25eeb5Syz155240 	{ "ttl invalid",		KSTAT_DATA_ULONG },
259ab25eeb5Syz155240 	{ "bad ip pkt",			KSTAT_DATA_ULONG },
260ab25eeb5Syz155240 	{ "ipv6 pkt",			KSTAT_DATA_ULONG },
261ab25eeb5Syz155240 	{ "dropped:pps ceiling",	KSTAT_DATA_ULONG },
262ab25eeb5Syz155240 	{ "ip upd. fail",		KSTAT_DATA_ULONG }
263ab25eeb5Syz155240 };
264ab25eeb5Syz155240 
265381a2a9aSdr146992 
266ab25eeb5Syz155240 static int	ipf_kstat_update(kstat_t *ksp, int rwflag);
267ab25eeb5Syz155240 
268ab25eeb5Syz155240 static void
269*94bdecd9SRob Gulewich ipf_kstat_init(ipf_stack_t *ifs, boolean_t from_gz)
270ab25eeb5Syz155240 {
271*94bdecd9SRob Gulewich 	ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid,
272*94bdecd9SRob Gulewich 	    (from_gz ? "ipf_gz" : "ipf"),
273*94bdecd9SRob Gulewich 	    0, "inbound", "net", KSTAT_TYPE_NAMED,
2747ddc9b1aSDarren Reed 	    sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
2757ddc9b1aSDarren Reed 	if (ifs->ifs_kstatp[0] != NULL) {
2767ddc9b1aSDarren Reed 		bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
277ab25eeb5Syz155240 		    sizeof (filter_kstats_t));
2787ddc9b1aSDarren Reed 		ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
2797ddc9b1aSDarren Reed 		ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
2807ddc9b1aSDarren Reed 		kstat_install(ifs->ifs_kstatp[0]);
281ab25eeb5Syz155240 	}
2827ddc9b1aSDarren Reed 
283*94bdecd9SRob Gulewich 	ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid,
284*94bdecd9SRob Gulewich 	    (from_gz ? "ipf_gz" : "ipf"),
285*94bdecd9SRob Gulewich 	    0, "outbound", "net", KSTAT_TYPE_NAMED,
2867ddc9b1aSDarren Reed 	    sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
2877ddc9b1aSDarren Reed 	if (ifs->ifs_kstatp[1] != NULL) {
2887ddc9b1aSDarren Reed 		bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
2897ddc9b1aSDarren Reed 		    sizeof (filter_kstats_t));
2907ddc9b1aSDarren Reed 		ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
2917ddc9b1aSDarren Reed 		ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
2927ddc9b1aSDarren Reed 		kstat_install(ifs->ifs_kstatp[1]);
293ab25eeb5Syz155240 	}
294ab25eeb5Syz155240 
295ab25eeb5Syz155240 #ifdef	IPFDEBUG
2967ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
2977ddc9b1aSDarren Reed 	    ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
298ab25eeb5Syz155240 #endif
299ab25eeb5Syz155240 }
300ab25eeb5Syz155240 
3017ddc9b1aSDarren Reed 
302ab25eeb5Syz155240 static void
3037ddc9b1aSDarren Reed ipf_kstat_fini(ipf_stack_t *ifs)
304ab25eeb5Syz155240 {
305ab25eeb5Syz155240 	int i;
306f4b3ec61Sdh155122 
307ab25eeb5Syz155240 	for (i = 0; i < 2; i++) {
308f4b3ec61Sdh155122 		if (ifs->ifs_kstatp[i] != NULL) {
3097ddc9b1aSDarren Reed 			net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
310f4b3ec61Sdh155122 			ifs->ifs_kstatp[i] = NULL;
311ab25eeb5Syz155240 		}
312ab25eeb5Syz155240 	}
313ab25eeb5Syz155240 }
314ab25eeb5Syz155240 
3157ddc9b1aSDarren Reed 
316ab25eeb5Syz155240 static int
317ab25eeb5Syz155240 ipf_kstat_update(kstat_t *ksp, int rwflag)
318ab25eeb5Syz155240 {
319ab25eeb5Syz155240 	filter_kstats_t	*fkp;
320ab25eeb5Syz155240 	filterstats_t	*fsp;
321ab25eeb5Syz155240 
322f4b3ec61Sdh155122 	if (ksp == NULL || ksp->ks_data == NULL)
323f4b3ec61Sdh155122 		return (EIO);
324f4b3ec61Sdh155122 
325ab25eeb5Syz155240 	if (rwflag == KSTAT_WRITE)
326ab25eeb5Syz155240 		return (EACCES);
327ab25eeb5Syz155240 
328ab25eeb5Syz155240 	fkp = ksp->ks_data;
329ab25eeb5Syz155240 	fsp = ksp->ks_private;
330ab25eeb5Syz155240 
331ab25eeb5Syz155240 	fkp->fks_pass.value.ul		= fsp->fr_pass;
332ab25eeb5Syz155240 	fkp->fks_block.value.ul		= fsp->fr_block;
333ab25eeb5Syz155240 	fkp->fks_nom.value.ul		= fsp->fr_nom;
334ab25eeb5Syz155240 	fkp->fks_short.value.ul		= fsp->fr_short;
335ab25eeb5Syz155240 	fkp->fks_ppkl.value.ul		= fsp->fr_ppkl;
336ab25eeb5Syz155240 	fkp->fks_bpkl.value.ul		= fsp->fr_bpkl;
337ab25eeb5Syz155240 	fkp->fks_npkl.value.ul		= fsp->fr_npkl;
338ab25eeb5Syz155240 	fkp->fks_pkl.value.ul		= fsp->fr_pkl;
339ab25eeb5Syz155240 	fkp->fks_skip.value.ul		= fsp->fr_skip;
340ab25eeb5Syz155240 	fkp->fks_ret.value.ul		= fsp->fr_ret;
341ab25eeb5Syz155240 	fkp->fks_acct.value.ul		= fsp->fr_acct;
342ab25eeb5Syz155240 	fkp->fks_bnfr.value.ul		= fsp->fr_bnfr;
343ab25eeb5Syz155240 	fkp->fks_nfr.value.ul		= fsp->fr_nfr;
344ab25eeb5Syz155240 	fkp->fks_cfr.value.ul		= fsp->fr_cfr;
345ab25eeb5Syz155240 	fkp->fks_bads.value.ul		= fsp->fr_bads;
346ab25eeb5Syz155240 	fkp->fks_ads.value.ul		= fsp->fr_ads;
347ab25eeb5Syz155240 	fkp->fks_chit.value.ul		= fsp->fr_chit;
348ab25eeb5Syz155240 	fkp->fks_tcpbad.value.ul 	= fsp->fr_tcpbad;
349ab25eeb5Syz155240 	fkp->fks_pull[0].value.ul 	= fsp->fr_pull[0];
350ab25eeb5Syz155240 	fkp->fks_pull[1].value.ul 	= fsp->fr_pull[1];
351ab25eeb5Syz155240 	fkp->fks_badsrc.value.ul 	= fsp->fr_badsrc;
352ab25eeb5Syz155240 	fkp->fks_badttl.value.ul 	= fsp->fr_badttl;
353ab25eeb5Syz155240 	fkp->fks_bad.value.ul		= fsp->fr_bad;
354ab25eeb5Syz155240 	fkp->fks_ipv6.value.ul		= fsp->fr_ipv6;
355ab25eeb5Syz155240 	fkp->fks_ppshit.value.ul 	= fsp->fr_ppshit;
356ab25eeb5Syz155240 	fkp->fks_ipud.value.ul		= fsp->fr_ipud;
357ab25eeb5Syz155240 
358ab25eeb5Syz155240 	return (0);
359ab25eeb5Syz155240 }
360ab25eeb5Syz155240 
36119397407SSherry Moore int
36219397407SSherry Moore _init()
363ab25eeb5Syz155240 {
364ab25eeb5Syz155240 	int ipfinst;
365ab25eeb5Syz155240 
366ab25eeb5Syz155240 	ipfinst = mod_install(&modlink1);
367ab25eeb5Syz155240 #ifdef	IPFDEBUG
368ab25eeb5Syz155240 	cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
369ab25eeb5Syz155240 #endif
3707ddc9b1aSDarren Reed 	mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
37119397407SSherry Moore 	return (ipfinst);
372ab25eeb5Syz155240 }
373ab25eeb5Syz155240 
374ab25eeb5Syz155240 
37519397407SSherry Moore int
37619397407SSherry Moore _fini(void)
377ab25eeb5Syz155240 {
378ab25eeb5Syz155240 	int ipfinst;
379ab25eeb5Syz155240 
380ab25eeb5Syz155240 	ipfinst = mod_remove(&modlink1);
381ab25eeb5Syz155240 #ifdef	IPFDEBUG
382ab25eeb5Syz155240 	cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
383ab25eeb5Syz155240 #endif
38419397407SSherry Moore 	return (ipfinst);
385ab25eeb5Syz155240 }
386ab25eeb5Syz155240 
387ab25eeb5Syz155240 
38819397407SSherry Moore int
38919397407SSherry Moore _info(modinfop)
390ab25eeb5Syz155240 struct modinfo *modinfop;
391ab25eeb5Syz155240 {
392ab25eeb5Syz155240 	int ipfinst;
393ab25eeb5Syz155240 
394ab25eeb5Syz155240 	ipfinst = mod_info(&modlink1, modinfop);
395ab25eeb5Syz155240 #ifdef	IPFDEBUG
3967ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
397ab25eeb5Syz155240 #endif
39819397407SSherry Moore 	return (ipfinst);
399ab25eeb5Syz155240 }
400ab25eeb5Syz155240 
401ab25eeb5Syz155240 
402ab25eeb5Syz155240 #if SOLARIS2 < 10
403ab25eeb5Syz155240 static int ipf_identify(dip)
404ab25eeb5Syz155240 dev_info_t *dip;
405ab25eeb5Syz155240 {
406ab25eeb5Syz155240 #ifdef	IPFDEBUG
4077ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
408ab25eeb5Syz155240 #endif
409ab25eeb5Syz155240 	if (strcmp(ddi_get_name(dip), "ipf") == 0)
410ab25eeb5Syz155240 		return (DDI_IDENTIFIED);
411ab25eeb5Syz155240 	return (DDI_NOT_IDENTIFIED);
412ab25eeb5Syz155240 }
413ab25eeb5Syz155240 #endif
414ab25eeb5Syz155240 
415f4b3ec61Sdh155122 /*
416f4b3ec61Sdh155122  * Initialize things for IPF for each stack instance
417f4b3ec61Sdh155122  */
418f4b3ec61Sdh155122 static void *
419*94bdecd9SRob Gulewich ipf_stack_create_one(const netid_t id, const zoneid_t zid, boolean_t from_gz,
420*94bdecd9SRob Gulewich     ipf_stack_t *ifs_gz)
421f4b3ec61Sdh155122 {
422f4b3ec61Sdh155122 	ipf_stack_t	*ifs;
423f4b3ec61Sdh155122 
4247ddc9b1aSDarren Reed #ifdef IPFDEBUG
425*94bdecd9SRob Gulewich 	cmn_err(CE_NOTE, "IP Filter:stack_create_one id=%d global=%d", id,
426*94bdecd9SRob Gulewich 	    global);
427f4b3ec61Sdh155122 #endif
428f4b3ec61Sdh155122 
4297ddc9b1aSDarren Reed 	ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
430f4b3ec61Sdh155122 	bzero(ifs, sizeof (*ifs));
431f4b3ec61Sdh155122 
432f4b3ec61Sdh155122 	ifs->ifs_hook4_physical_in	= B_FALSE;
433f4b3ec61Sdh155122 	ifs->ifs_hook4_physical_out	= B_FALSE;
434f4b3ec61Sdh155122 	ifs->ifs_hook4_nic_events	= B_FALSE;
435f4b3ec61Sdh155122 	ifs->ifs_hook4_loopback_in	= B_FALSE;
436f4b3ec61Sdh155122 	ifs->ifs_hook4_loopback_out	= B_FALSE;
437f4b3ec61Sdh155122 	ifs->ifs_hook6_physical_in	= B_FALSE;
438f4b3ec61Sdh155122 	ifs->ifs_hook6_physical_out	= B_FALSE;
439f4b3ec61Sdh155122 	ifs->ifs_hook6_nic_events	= B_FALSE;
440f4b3ec61Sdh155122 	ifs->ifs_hook6_loopback_in	= B_FALSE;
441f4b3ec61Sdh155122 	ifs->ifs_hook6_loopback_out	= B_FALSE;
442f4b3ec61Sdh155122 
443f4b3ec61Sdh155122 	/*
444f4b3ec61Sdh155122 	 * Initialize mutex's
445f4b3ec61Sdh155122 	 */
446f4b3ec61Sdh155122 	RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
447f4b3ec61Sdh155122 	RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
44814d3298eSAlexandr Nedvedicky 	RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
4497ddc9b1aSDarren Reed 	ifs->ifs_netid = id;
450*94bdecd9SRob Gulewich 	ifs->ifs_zone = zid;
451*94bdecd9SRob Gulewich 	ifs->ifs_gz_controlled = from_gz;
452*94bdecd9SRob Gulewich 	ifs->ifs_gz_cont_ifs = ifs_gz;
453*94bdecd9SRob Gulewich 
454*94bdecd9SRob Gulewich 	ipf_kstat_init(ifs, from_gz);
4557ddc9b1aSDarren Reed 
4567ddc9b1aSDarren Reed #ifdef IPFDEBUG
4577ddc9b1aSDarren Reed 	cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
458f4b3ec61Sdh155122 #endif
459f4b3ec61Sdh155122 
460f4b3ec61Sdh155122 	/*
461f4b3ec61Sdh155122 	 * Lock people out while we set things up.
462f4b3ec61Sdh155122 	 */
463f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_global);
464f4b3ec61Sdh155122 	ipftuneable_alloc(ifs);
465f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
466f4b3ec61Sdh155122 
46723f4867fSnordmark 	/* Limit to global stack */
4687ddc9b1aSDarren Reed 	if (ifs->ifs_zone == GLOBAL_ZONEID)
469f4b3ec61Sdh155122 		cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
47023f4867fSnordmark 
4717ddc9b1aSDarren Reed 	mutex_enter(&ipf_stack_lock);
4727ddc9b1aSDarren Reed 	if (ipf_stacks != NULL)
4737ddc9b1aSDarren Reed 		ipf_stacks->ifs_pnext = &ifs->ifs_next;
4747ddc9b1aSDarren Reed 	ifs->ifs_next = ipf_stacks;
4757ddc9b1aSDarren Reed 	ifs->ifs_pnext = &ipf_stacks;
4767ddc9b1aSDarren Reed 	ipf_stacks = ifs;
4777ddc9b1aSDarren Reed 	mutex_exit(&ipf_stack_lock);
4787ddc9b1aSDarren Reed 
479f4b3ec61Sdh155122 	return (ifs);
480f4b3ec61Sdh155122 }
481f4b3ec61Sdh155122 
482*94bdecd9SRob Gulewich static void *
483*94bdecd9SRob Gulewich ipf_stack_create(const netid_t id)
484*94bdecd9SRob Gulewich {
485*94bdecd9SRob Gulewich 	ipf_stack_t	*ifs = NULL;
486*94bdecd9SRob Gulewich 	zoneid_t	zid = net_getzoneidbynetid(id);
4877ddc9b1aSDarren Reed 
4887ddc9b1aSDarren Reed 	/*
489*94bdecd9SRob Gulewich 	 * Create two ipfilter stacks for a zone - the first can only be
490*94bdecd9SRob Gulewich 	 * controlled from the global zone, and the second is owned by
491*94bdecd9SRob Gulewich 	 * the zone itself. There is no need to create a GZ-controlled
492*94bdecd9SRob Gulewich 	 * stack for the global zone, since we're already in the global
493*94bdecd9SRob Gulewich 	 * zone. See the "GZ-controlled and per-zone stacks" comment block in
494*94bdecd9SRob Gulewich 	 * ip_fil_solaris.c for details.
495*94bdecd9SRob Gulewich 	 */
496*94bdecd9SRob Gulewich 	if (zid != GLOBAL_ZONEID)
497*94bdecd9SRob Gulewich 		ifs = ipf_stack_create_one(id, zid, B_TRUE, NULL);
498*94bdecd9SRob Gulewich 
499*94bdecd9SRob Gulewich 	return (ipf_stack_create_one(id, zid, B_FALSE, ifs));
500*94bdecd9SRob Gulewich }
501*94bdecd9SRob Gulewich 
502*94bdecd9SRob Gulewich /*
503*94bdecd9SRob Gulewich  * Find an ipfilter stack for the given zone. Return the GZ-controlled or
504*94bdecd9SRob Gulewich  * per-zone stack if set by an earlier SIOCIPFZONESET ioctl call. See the
505*94bdecd9SRob Gulewich  * "GZ-controlled and per-zone stacks" comment block in ip_fil_solaris.c for
506*94bdecd9SRob Gulewich  * details.
507*94bdecd9SRob Gulewich  *
508*94bdecd9SRob Gulewich  * This function returns with the ipf_stack_t's ifs_ipf_global
509*94bdecd9SRob Gulewich  * read lock held (if the stack is found). See the "ipfilter kernel module
510*94bdecd9SRob Gulewich  * mutexes and locking" comment block at the top of this file.
5117ddc9b1aSDarren Reed  */
51219397407SSherry Moore ipf_stack_t *
513*94bdecd9SRob Gulewich ipf_find_stack(const zoneid_t orig_zone, ipf_devstate_t *isp)
5147ddc9b1aSDarren Reed {
5157ddc9b1aSDarren Reed 	ipf_stack_t *ifs;
516*94bdecd9SRob Gulewich 	boolean_t gz_stack;
517*94bdecd9SRob Gulewich 	zoneid_t zone;
518*94bdecd9SRob Gulewich 
519*94bdecd9SRob Gulewich 	/*
520*94bdecd9SRob Gulewich 	 * If we're in the GZ, determine if we're acting on a zone's stack,
521*94bdecd9SRob Gulewich 	 * and whether or not that stack is the GZ-controlled or in-zone
522*94bdecd9SRob Gulewich 	 * one.  See the "GZ and per-zone stacks" note at the top of this
523*94bdecd9SRob Gulewich 	 * file.
524*94bdecd9SRob Gulewich 	 */
525*94bdecd9SRob Gulewich 	if (orig_zone == GLOBAL_ZONEID &&
526*94bdecd9SRob Gulewich 	    (isp->ipfs_zoneid != IPFS_ZONE_UNSET)) {
527*94bdecd9SRob Gulewich 		/* Global zone, and we've set the zoneid for this fd already */
528*94bdecd9SRob Gulewich 
529*94bdecd9SRob Gulewich 		if (orig_zone == isp->ipfs_zoneid) {
530*94bdecd9SRob Gulewich 			/* There's only a per-zone stack for the GZ */
531*94bdecd9SRob Gulewich 			gz_stack = B_FALSE;
532*94bdecd9SRob Gulewich 		} else {
533*94bdecd9SRob Gulewich 			gz_stack = isp->ipfs_gz;
534*94bdecd9SRob Gulewich 		}
535*94bdecd9SRob Gulewich 
536*94bdecd9SRob Gulewich 		zone = isp->ipfs_zoneid;
537*94bdecd9SRob Gulewich 	} else {
538*94bdecd9SRob Gulewich 		/*
539*94bdecd9SRob Gulewich 		 * Non-global zone or GZ without having set a zoneid: act on
540*94bdecd9SRob Gulewich 		 * the per-zone stack of the zone that this ioctl originated
541*94bdecd9SRob Gulewich 		 * from.
542*94bdecd9SRob Gulewich 		 */
543*94bdecd9SRob Gulewich 		gz_stack = B_FALSE;
544*94bdecd9SRob Gulewich 		zone = orig_zone;
545*94bdecd9SRob Gulewich 	}
5467ddc9b1aSDarren Reed 
5477ddc9b1aSDarren Reed 	mutex_enter(&ipf_stack_lock);
5487ddc9b1aSDarren Reed 	for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
549*94bdecd9SRob Gulewich 		if (ifs->ifs_zone == zone && ifs->ifs_gz_controlled == gz_stack)
5507ddc9b1aSDarren Reed 			break;
5517ddc9b1aSDarren Reed 	}
552*94bdecd9SRob Gulewich 
553*94bdecd9SRob Gulewich 	if (ifs != NULL) {
554*94bdecd9SRob Gulewich 		READ_ENTER(&ifs->ifs_ipf_global);
555*94bdecd9SRob Gulewich 	}
5567ddc9b1aSDarren Reed 	mutex_exit(&ipf_stack_lock);
55719397407SSherry Moore 	return (ifs);
5587ddc9b1aSDarren Reed }
5597ddc9b1aSDarren Reed 
560f4b3ec61Sdh155122 static int ipf_detach_check_zone(ipf_stack_t *ifs)
561f4b3ec61Sdh155122 {
562f4b3ec61Sdh155122 	/*
563f4b3ec61Sdh155122 	 * Make sure we're the only one's modifying things.  With
564f4b3ec61Sdh155122 	 * this lock others should just fall out of the loop.
565f4b3ec61Sdh155122 	 */
566f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_global);
567f4b3ec61Sdh155122 	if (ifs->ifs_fr_running == 1) {
568f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
569f4b3ec61Sdh155122 		return (-1);
570f4b3ec61Sdh155122 	}
571f4b3ec61Sdh155122 
572f4b3ec61Sdh155122 	/*
573f4b3ec61Sdh155122 	 * Make sure there is no active filter rule.
574f4b3ec61Sdh155122 	 */
575f4b3ec61Sdh155122 	if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
576f4b3ec61Sdh155122 	    ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
577f4b3ec61Sdh155122 	    ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
578f4b3ec61Sdh155122 	    ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
579f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
580f4b3ec61Sdh155122 		return (-1);
581f4b3ec61Sdh155122 	}
582f4b3ec61Sdh155122 
583f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
584f4b3ec61Sdh155122 
585f4b3ec61Sdh155122 	return (0);
586f4b3ec61Sdh155122 }
587f4b3ec61Sdh155122 
5887ddc9b1aSDarren Reed 
589f4b3ec61Sdh155122 static int ipf_detach_check_all()
590f4b3ec61Sdh155122 {
5917ddc9b1aSDarren Reed 	ipf_stack_t *ifs;
592f4b3ec61Sdh155122 
5937ddc9b1aSDarren Reed 	mutex_enter(&ipf_stack_lock);
5947ddc9b1aSDarren Reed 	for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
5957ddc9b1aSDarren Reed 		if (ipf_detach_check_zone(ifs) != 0)
5967ddc9b1aSDarren Reed 			break;
5977ddc9b1aSDarren Reed 	mutex_exit(&ipf_stack_lock);
5987ddc9b1aSDarren Reed 	return ((ifs == NULL) ? 0 : -1);
599f4b3ec61Sdh155122 }
600f4b3ec61Sdh155122 
601f4b3ec61Sdh155122 
602f4b3ec61Sdh155122 /*
603*94bdecd9SRob Gulewich  * Remove ipf kstats for both the per-zone ipf stack and the
604*94bdecd9SRob Gulewich  * GZ-controlled stack for the same zone, if it exists.
605f4b3ec61Sdh155122  */
606f4b3ec61Sdh155122 /* ARGSUSED */
607f4b3ec61Sdh155122 static void
6088ad74188SDarren Reed ipf_stack_shutdown(const netid_t id, void *arg)
6098ad74188SDarren Reed {
6108ad74188SDarren Reed 	ipf_stack_t *ifs = (ipf_stack_t *)arg;
6118ad74188SDarren Reed 
612*94bdecd9SRob Gulewich 	/*
613*94bdecd9SRob Gulewich 	 * The GZ-controlled stack
614*94bdecd9SRob Gulewich 	 */
615*94bdecd9SRob Gulewich 	if (ifs->ifs_gz_cont_ifs != NULL)
616*94bdecd9SRob Gulewich 		ipf_kstat_fini(ifs->ifs_gz_cont_ifs);
617*94bdecd9SRob Gulewich 
618*94bdecd9SRob Gulewich 	/*
619*94bdecd9SRob Gulewich 	 * The per-zone stack
620*94bdecd9SRob Gulewich 	 */
6218ad74188SDarren Reed 	ipf_kstat_fini(ifs);
6228ad74188SDarren Reed }
6238ad74188SDarren Reed 
6248ad74188SDarren Reed 
6258ad74188SDarren Reed /*
6268ad74188SDarren Reed  * Destroy things for ipf for one stack.
6278ad74188SDarren Reed  */
6288ad74188SDarren Reed /* ARGSUSED */
6298ad74188SDarren Reed static void
630*94bdecd9SRob Gulewich ipf_stack_destroy_one(const netid_t id, ipf_stack_t *ifs)
631f4b3ec61Sdh155122 {
6327ddc9b1aSDarren Reed 	timeout_id_t tid;
633f4b3ec61Sdh155122 
6347ddc9b1aSDarren Reed #ifdef IPFDEBUG
635*94bdecd9SRob Gulewich 	(void) printf("ipf_stack_destroy_one(%p)\n", (void *)ifs);
636f4b3ec61Sdh155122 #endif
637f4b3ec61Sdh155122 
638f4b3ec61Sdh155122 	/*
639f4b3ec61Sdh155122 	 * Make sure we're the only one's modifying things.  With
640f4b3ec61Sdh155122 	 * this lock others should just fall out of the loop.
641f4b3ec61Sdh155122 	 */
642f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_global);
643f4b3ec61Sdh155122 	if (ifs->ifs_fr_running == -2) {
644f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
645f4b3ec61Sdh155122 		return;
646f4b3ec61Sdh155122 	}
647f4b3ec61Sdh155122 	ifs->ifs_fr_running = -2;
6487ddc9b1aSDarren Reed 	tid = ifs->ifs_fr_timer_id;
6497ddc9b1aSDarren Reed 	ifs->ifs_fr_timer_id = NULL;
650f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
651f4b3ec61Sdh155122 
6527ddc9b1aSDarren Reed 	mutex_enter(&ipf_stack_lock);
6537ddc9b1aSDarren Reed 	if (ifs->ifs_next != NULL)
6547ddc9b1aSDarren Reed 		ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
6557ddc9b1aSDarren Reed 	*ifs->ifs_pnext = ifs->ifs_next;
6567ddc9b1aSDarren Reed 	mutex_exit(&ipf_stack_lock);
6577ddc9b1aSDarren Reed 
6587ddc9b1aSDarren Reed 	if (tid != NULL)
6597ddc9b1aSDarren Reed 		(void) untimeout(tid);
660f4b3ec61Sdh155122 
661f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_global);
662f4b3ec61Sdh155122 	if (ipldetach(ifs) != 0) {
663*94bdecd9SRob Gulewich 		printf("ipf_stack_destroy_one: ipldetach failed\n");
664f4b3ec61Sdh155122 	}
665f4b3ec61Sdh155122 
666f4b3ec61Sdh155122 	ipftuneable_free(ifs);
667f4b3ec61Sdh155122 
668f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
669f4b3ec61Sdh155122 	RW_DESTROY(&ifs->ifs_ipf_mutex);
67014d3298eSAlexandr Nedvedicky 	RW_DESTROY(&ifs->ifs_ipf_frcache);
671f4b3ec61Sdh155122 	RW_DESTROY(&ifs->ifs_ipf_global);
672f4b3ec61Sdh155122 
673f4b3ec61Sdh155122 	KFREE(ifs);
674f4b3ec61Sdh155122 }
675ab25eeb5Syz155240 
6767ddc9b1aSDarren Reed 
677*94bdecd9SRob Gulewich /*
678*94bdecd9SRob Gulewich  * Destroy things for ipf for both the per-zone ipf stack and the
679*94bdecd9SRob Gulewich  * GZ-controlled stack for the same zone, if it exists. See the "GZ-controlled
680*94bdecd9SRob Gulewich  * and per-zone stacks" comment block in ip_fil_solaris.c for details.
681*94bdecd9SRob Gulewich  */
682*94bdecd9SRob Gulewich /* ARGSUSED */
683*94bdecd9SRob Gulewich static void
684*94bdecd9SRob Gulewich ipf_stack_destroy(const netid_t id, void *arg)
685*94bdecd9SRob Gulewich {
686*94bdecd9SRob Gulewich 	ipf_stack_t *ifs = (ipf_stack_t *)arg;
687*94bdecd9SRob Gulewich 
688*94bdecd9SRob Gulewich 	/*
689*94bdecd9SRob Gulewich 	 * The GZ-controlled stack
690*94bdecd9SRob Gulewich 	 */
691*94bdecd9SRob Gulewich 	if (ifs->ifs_gz_cont_ifs != NULL)
692*94bdecd9SRob Gulewich 		ipf_stack_destroy_one(id, ifs->ifs_gz_cont_ifs);
693*94bdecd9SRob Gulewich 
694*94bdecd9SRob Gulewich 	/*
695*94bdecd9SRob Gulewich 	 * The per-zone stack
696*94bdecd9SRob Gulewich 	 */
697*94bdecd9SRob Gulewich 	ipf_stack_destroy_one(id, ifs);
698*94bdecd9SRob Gulewich }
699*94bdecd9SRob Gulewich 
700*94bdecd9SRob Gulewich 
701ab25eeb5Syz155240 static int ipf_attach(dip, cmd)
702ab25eeb5Syz155240 dev_info_t *dip;
703ab25eeb5Syz155240 ddi_attach_cmd_t cmd;
704ab25eeb5Syz155240 {
705ab25eeb5Syz155240 	char *s;
706ab25eeb5Syz155240 	int i;
707ab25eeb5Syz155240 	int instance;
708ab25eeb5Syz155240 
709ab25eeb5Syz155240 #ifdef	IPFDEBUG
7107ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
711ab25eeb5Syz155240 #endif
712ab25eeb5Syz155240 
713ab25eeb5Syz155240 	switch (cmd)
714ab25eeb5Syz155240 	{
715ab25eeb5Syz155240 	case DDI_ATTACH:
716ab25eeb5Syz155240 		instance = ddi_get_instance(dip);
717ab25eeb5Syz155240 		/* Only one instance of ipf (instance 0) can be attached. */
718ab25eeb5Syz155240 		if (instance > 0)
71919397407SSherry Moore 			return (DDI_FAILURE);
720ab25eeb5Syz155240 
721ab25eeb5Syz155240 #ifdef	IPFDEBUG
7227ddc9b1aSDarren Reed 		cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
723ab25eeb5Syz155240 #endif
724ab25eeb5Syz155240 
725f4b3ec61Sdh155122 		(void) ipf_property_g_update(dip);
726ab25eeb5Syz155240 
727*94bdecd9SRob Gulewich 		if (ddi_soft_state_init(&ipf_state, sizeof (ipf_devstate_t), 1)
728*94bdecd9SRob Gulewich 		    != 0) {
729*94bdecd9SRob Gulewich 			ddi_prop_remove_all(dip);
730*94bdecd9SRob Gulewich 			return (DDI_FAILURE);
731*94bdecd9SRob Gulewich 		}
732*94bdecd9SRob Gulewich 
733ab25eeb5Syz155240 		for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
734ab25eeb5Syz155240 			s = strrchr(s, '/');
735ab25eeb5Syz155240 			if (s == NULL)
736ab25eeb5Syz155240 				continue;
737ab25eeb5Syz155240 			s++;
738ab25eeb5Syz155240 			if (ddi_create_minor_node(dip, s, S_IFCHR, i,
739*94bdecd9SRob Gulewich 			    DDI_PSEUDO, 0) == DDI_FAILURE)
740ab25eeb5Syz155240 				goto attach_failed;
741ab25eeb5Syz155240 		}
742ab25eeb5Syz155240 
743ab25eeb5Syz155240 		ipf_dev_info = dip;
7447ddc9b1aSDarren Reed 
7457ddc9b1aSDarren Reed 		ipfncb = net_instance_alloc(NETINFO_VERSION);
746*94bdecd9SRob Gulewich 		if (ipfncb == NULL)
747*94bdecd9SRob Gulewich 			goto attach_failed;
748*94bdecd9SRob Gulewich 
7497ddc9b1aSDarren Reed 		ipfncb->nin_name = "ipf";
7507ddc9b1aSDarren Reed 		ipfncb->nin_create = ipf_stack_create;
7517ddc9b1aSDarren Reed 		ipfncb->nin_destroy = ipf_stack_destroy;
7528ad74188SDarren Reed 		ipfncb->nin_shutdown = ipf_stack_shutdown;
753*94bdecd9SRob Gulewich 		if (net_instance_register(ipfncb) == DDI_FAILURE) {
754*94bdecd9SRob Gulewich 			net_instance_free(ipfncb);
755*94bdecd9SRob Gulewich 			goto attach_failed;
756*94bdecd9SRob Gulewich 		}
757*94bdecd9SRob Gulewich 
758*94bdecd9SRob Gulewich 		ipf_minor = vmem_create("ipf_minor", (void *)1, UINT32_MAX - 1,
759*94bdecd9SRob Gulewich 		    1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
7607ddc9b1aSDarren Reed 
7617ddc9b1aSDarren Reed #ifdef IPFDEBUG
7627ddc9b1aSDarren Reed 		cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
7637ddc9b1aSDarren Reed #endif
7647ddc9b1aSDarren Reed 
76519397407SSherry Moore 		return (DDI_SUCCESS);
766ab25eeb5Syz155240 		/* NOTREACHED */
767ab25eeb5Syz155240 	default:
768ab25eeb5Syz155240 		break;
769ab25eeb5Syz155240 	}
770ab25eeb5Syz155240 
771ab25eeb5Syz155240 attach_failed:
772*94bdecd9SRob Gulewich 	ddi_remove_minor_node(dip, NULL);
773f4b3ec61Sdh155122 	ddi_prop_remove_all(dip);
774*94bdecd9SRob Gulewich 	ddi_soft_state_fini(&ipf_state);
77519397407SSherry Moore 	return (DDI_FAILURE);
776ab25eeb5Syz155240 }
777ab25eeb5Syz155240 
778ab25eeb5Syz155240 
779ab25eeb5Syz155240 static int ipf_detach(dip, cmd)
780ab25eeb5Syz155240 dev_info_t *dip;
781ab25eeb5Syz155240 ddi_detach_cmd_t cmd;
782ab25eeb5Syz155240 {
783ab25eeb5Syz155240 	int i;
784ab25eeb5Syz155240 
785ab25eeb5Syz155240 #ifdef	IPFDEBUG
7867ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
787ab25eeb5Syz155240 #endif
788ab25eeb5Syz155240 	switch (cmd) {
789ab25eeb5Syz155240 	case DDI_DETACH:
790f4b3ec61Sdh155122 		if (ipf_detach_check_all() != 0)
79119397407SSherry Moore 			return (DDI_FAILURE);
792ab25eeb5Syz155240 
79319397407SSherry Moore 		/*
79419397407SSherry Moore 		 * Undo what we did in ipf_attach, freeing resources
795ab25eeb5Syz155240 		 * and removing things we installed.  The system
796ab25eeb5Syz155240 		 * framework guarantees we are not active with this devinfo
797ab25eeb5Syz155240 		 * node in any other entry points at this time.
798ab25eeb5Syz155240 		 */
799ab25eeb5Syz155240 		ddi_prop_remove_all(dip);
800ab25eeb5Syz155240 		i = ddi_get_instance(dip);
801ab25eeb5Syz155240 		ddi_remove_minor_node(dip, NULL);
802ab25eeb5Syz155240 		if (i > 0) {
803ab25eeb5Syz155240 			cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
80419397407SSherry Moore 			return (DDI_FAILURE);
805ab25eeb5Syz155240 		}
806ab25eeb5Syz155240 
807*94bdecd9SRob Gulewich 		vmem_destroy(ipf_minor);
808*94bdecd9SRob Gulewich 		ddi_soft_state_fini(&ipf_state);
809*94bdecd9SRob Gulewich 
8107ddc9b1aSDarren Reed 		(void) net_instance_unregister(ipfncb);
8117ddc9b1aSDarren Reed 		net_instance_free(ipfncb);
8127ddc9b1aSDarren Reed 
81319397407SSherry Moore 		return (DDI_SUCCESS);
814f4b3ec61Sdh155122 		/* NOTREACHED */
815ab25eeb5Syz155240 	default:
816ab25eeb5Syz155240 		break;
817ab25eeb5Syz155240 	}
818ab25eeb5Syz155240 	cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
81919397407SSherry Moore 	return (DDI_FAILURE);
820ab25eeb5Syz155240 }
821ab25eeb5Syz155240 
822ab25eeb5Syz155240 
823ab25eeb5Syz155240 /*ARGSUSED*/
824ab25eeb5Syz155240 static int ipf_getinfo(dip, infocmd, arg, result)
825ab25eeb5Syz155240 dev_info_t *dip;
826ab25eeb5Syz155240 ddi_info_cmd_t infocmd;
827ab25eeb5Syz155240 void *arg, **result;
828ab25eeb5Syz155240 {
829ab25eeb5Syz155240 	int error;
830ab25eeb5Syz155240 
831ab25eeb5Syz155240 	error = DDI_FAILURE;
832ab25eeb5Syz155240 #ifdef	IPFDEBUG
8337ddc9b1aSDarren Reed 	cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
834ab25eeb5Syz155240 #endif
835ab25eeb5Syz155240 	switch (infocmd) {
836ab25eeb5Syz155240 	case DDI_INFO_DEVT2DEVINFO:
837ab25eeb5Syz155240 		*result = ipf_dev_info;
838ab25eeb5Syz155240 		error = DDI_SUCCESS;
839ab25eeb5Syz155240 		break;
840ab25eeb5Syz155240 	case DDI_INFO_DEVT2INSTANCE:
841ab25eeb5Syz155240 		*result = (void *)0;
842ab25eeb5Syz155240 		error = DDI_SUCCESS;
843ab25eeb5Syz155240 		break;
844ab25eeb5Syz155240 	default:
845ab25eeb5Syz155240 		break;
846ab25eeb5Syz155240 	}
847ab25eeb5Syz155240 	return (error);
848ab25eeb5Syz155240 }
849ab25eeb5Syz155240 
850ab25eeb5Syz155240 
851ab25eeb5Syz155240 /*
852ab25eeb5Syz155240  * Fetch configuration file values that have been entered into the ipf.conf
853ab25eeb5Syz155240  * driver file.
854ab25eeb5Syz155240  */
855f4b3ec61Sdh155122 static int ipf_property_g_update(dip)
856ab25eeb5Syz155240 dev_info_t *dip;
857ab25eeb5Syz155240 {
858ab25eeb5Syz155240 #ifdef DDI_NO_AUTODETACH
859ab25eeb5Syz155240 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
860ab25eeb5Syz155240 				DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
861ab25eeb5Syz155240 		cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
86219397407SSherry Moore 		return (DDI_FAILURE);
863ab25eeb5Syz155240 	}
864ab25eeb5Syz155240 #else
865ab25eeb5Syz155240 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
866ab25eeb5Syz155240 				"ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
867ab25eeb5Syz155240 		cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
86819397407SSherry Moore 		return (DDI_FAILURE);
869ab25eeb5Syz155240 	}
870ab25eeb5Syz155240 #endif
871ab25eeb5Syz155240 
87219397407SSherry Moore 	return (DDI_SUCCESS);
873f4b3ec61Sdh155122 }
874f4b3ec61Sdh155122 
87519397407SSherry Moore int
87619397407SSherry Moore ipf_property_update(dip, ifs)
877f4b3ec61Sdh155122 dev_info_t *dip;
878f4b3ec61Sdh155122 ipf_stack_t *ifs;
879f4b3ec61Sdh155122 {
880f4b3ec61Sdh155122 	ipftuneable_t *ipft;
881f4b3ec61Sdh155122 	char *name;
88219397407SSherry Moore 	uint_t one;
883f4b3ec61Sdh155122 	int *i32p;
88440cdc2e8SAlexandr Nedvedicky 	int err, rv = 0;
885f4b3ec61Sdh155122 
88640cdc2e8SAlexandr Nedvedicky 	for (ipft = ifs->ifs_ipf_tuneables;
88740cdc2e8SAlexandr Nedvedicky 		(name = ipft->ipft_name) != NULL; ipft++) {
888ab25eeb5Syz155240 		one = 1;
889ab25eeb5Syz155240 		i32p = NULL;
890ab25eeb5Syz155240 		err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
891ab25eeb5Syz155240 						0, name, &i32p, &one);
892ab25eeb5Syz155240 		if (err == DDI_PROP_NOT_FOUND)
893ab25eeb5Syz155240 			continue;
894ab25eeb5Syz155240 #ifdef	IPFDEBUG
895ab25eeb5Syz155240 		cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
896ab25eeb5Syz155240 			name, err);
897ab25eeb5Syz155240 #endif
89840cdc2e8SAlexandr Nedvedicky 		if (err != DDI_PROP_SUCCESS) {
89940cdc2e8SAlexandr Nedvedicky 			rv = err;
900ab25eeb5Syz155240 			continue;
901ab25eeb5Syz155240 		}
90240cdc2e8SAlexandr Nedvedicky 
90340cdc2e8SAlexandr Nedvedicky 		if (*i32p >= ipft->ipft_min &&
90440cdc2e8SAlexandr Nedvedicky 		    *i32p <= ipft->ipft_max) {
90540cdc2e8SAlexandr Nedvedicky 			if (ipft->ipft_sz == sizeof (uint32_t)) {
90640cdc2e8SAlexandr Nedvedicky 				*ipft->ipft_pint = *i32p;
90740cdc2e8SAlexandr Nedvedicky 			} else if (ipft->ipft_sz == sizeof (uint64_t)) {
90840cdc2e8SAlexandr Nedvedicky 				*ipft->ipft_plong = *i32p;
909ab25eeb5Syz155240 			}
91040cdc2e8SAlexandr Nedvedicky 		}
91140cdc2e8SAlexandr Nedvedicky 
91240cdc2e8SAlexandr Nedvedicky 		ddi_prop_free(i32p);
91340cdc2e8SAlexandr Nedvedicky 	}
91440cdc2e8SAlexandr Nedvedicky 
91540cdc2e8SAlexandr Nedvedicky 	return (rv);
916ab25eeb5Syz155240 }
917