xref: /illumos-gate/usr/src/uts/common/inet/ipf/solaris.c (revision f4b3ec61)
1ab25eeb5Syz /*
2ab25eeb5Syz  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3ab25eeb5Syz  *
4ab25eeb5Syz  * See the IPFILTER.LICENCE file for details on licencing.
5ab25eeb5Syz  *
6*f4b3ec61Sdh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
7ab25eeb5Syz  * Use is subject to license terms.
8ab25eeb5Syz  */
9ab25eeb5Syz /* #pragma ident   "@(#)solaris.c	1.12 6/5/96 (C) 1995 Darren Reed"*/
10ab25eeb5Syz #pragma ident "@(#)$Id: solaris.c,v 2.73.2.6 2005/07/13 21:40:47 darrenr Exp $"
11ab25eeb5Syz 
12ab25eeb5Syz #pragma ident	"%Z%%M%	%I%	%E% SMI"
13ab25eeb5Syz 
14ab25eeb5Syz #include <sys/systm.h>
15ab25eeb5Syz #include <sys/types.h>
16ab25eeb5Syz #include <sys/param.h>
17ab25eeb5Syz #include <sys/errno.h>
18ab25eeb5Syz #include <sys/uio.h>
19ab25eeb5Syz #include <sys/buf.h>
20ab25eeb5Syz #include <sys/modctl.h>
21ab25eeb5Syz #include <sys/open.h>
22ab25eeb5Syz #include <sys/kmem.h>
23ab25eeb5Syz #include <sys/conf.h>
24ab25eeb5Syz #include <sys/cmn_err.h>
25ab25eeb5Syz #include <sys/stat.h>
26ab25eeb5Syz #include <sys/cred.h>
27ab25eeb5Syz #include <sys/dditypes.h>
28ab25eeb5Syz #include <sys/poll.h>
29ab25eeb5Syz #include <sys/autoconf.h>
30ab25eeb5Syz #include <sys/byteorder.h>
31ab25eeb5Syz #include <sys/socket.h>
32ab25eeb5Syz #include <sys/dlpi.h>
33ab25eeb5Syz #include <sys/stropts.h>
34ab25eeb5Syz #include <sys/kstat.h>
35ab25eeb5Syz #include <sys/sockio.h>
36381a2a9aSdr #include <sys/neti.h>
37381a2a9aSdr #include <sys/hook.h>
38ab25eeb5Syz #include <net/if.h>
39ab25eeb5Syz #if SOLARIS2 >= 6
40ab25eeb5Syz # include <net/if_types.h>
41ab25eeb5Syz #endif
42*f4b3ec61Sdh #include <sys/netstack.h>
43ab25eeb5Syz #include <net/af.h>
44ab25eeb5Syz #include <net/route.h>
45ab25eeb5Syz #include <netinet/in.h>
46ab25eeb5Syz #include <netinet/in_systm.h>
47ab25eeb5Syz #include <netinet/if_ether.h>
48ab25eeb5Syz #include <netinet/ip.h>
49ab25eeb5Syz #include <netinet/ip_var.h>
50ab25eeb5Syz #include <netinet/tcp.h>
51ab25eeb5Syz #include <netinet/udp.h>
52ab25eeb5Syz #include <netinet/tcpip.h>
53ab25eeb5Syz #include <netinet/ip_icmp.h>
54ab25eeb5Syz #include <sys/ddi.h>
55ab25eeb5Syz #include <sys/sunddi.h>
56ab25eeb5Syz #include "netinet/ip_compat.h"
57ab25eeb5Syz #include "netinet/ipl.h"
58ab25eeb5Syz #include "netinet/ip_fil.h"
59ab25eeb5Syz #include "netinet/ip_nat.h"
60ab25eeb5Syz #include "netinet/ip_frag.h"
61ab25eeb5Syz #include "netinet/ip_auth.h"
62ab25eeb5Syz #include "netinet/ip_state.h"
63*f4b3ec61Sdh #include "netinet/ipf_stack.h"
64ab25eeb5Syz 
65ab25eeb5Syz extern	int	iplwrite __P((dev_t, struct uio *, cred_t *));
66ab25eeb5Syz 
67ab25eeb5Syz static	int	ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
68ab25eeb5Syz 				 void *, void **));
69ab25eeb5Syz #if SOLARIS2 < 10
70ab25eeb5Syz static	int	ipf_identify __P((dev_info_t *));
71ab25eeb5Syz #endif
72ab25eeb5Syz static	int	ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
73ab25eeb5Syz static	int	ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
74*f4b3ec61Sdh static	int	ipf_property_g_update __P((dev_info_t *));
75ab25eeb5Syz static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
76ab25eeb5Syz 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
77ab25eeb5Syz 				    IPLOOKUP_NAME, NULL };
78ab25eeb5Syz 
79ab25eeb5Syz 
80ab25eeb5Syz static struct cb_ops ipf_cb_ops = {
81ab25eeb5Syz 	iplopen,
82ab25eeb5Syz 	iplclose,
83ab25eeb5Syz 	nodev,		/* strategy */
84ab25eeb5Syz 	nodev,		/* print */
85ab25eeb5Syz 	nodev,		/* dump */
86ab25eeb5Syz 	iplread,
87ab25eeb5Syz 	iplwrite,	/* write */
88ab25eeb5Syz 	iplioctl,	/* ioctl */
89ab25eeb5Syz 	nodev,		/* devmap */
90ab25eeb5Syz 	nodev,		/* mmap */
91ab25eeb5Syz 	nodev,		/* segmap */
92ab25eeb5Syz 	nochpoll,	/* poll */
93ab25eeb5Syz 	ddi_prop_op,
94ab25eeb5Syz 	NULL,
95ab25eeb5Syz 	D_MTSAFE,
96ab25eeb5Syz #if SOLARIS2 > 4
97ab25eeb5Syz 	CB_REV,
98ab25eeb5Syz 	nodev,		/* aread */
99ab25eeb5Syz 	nodev,		/* awrite */
100ab25eeb5Syz #endif
101ab25eeb5Syz };
102ab25eeb5Syz 
103ab25eeb5Syz static struct dev_ops ipf_ops = {
104ab25eeb5Syz 	DEVO_REV,
105ab25eeb5Syz 	0,
106ab25eeb5Syz 	ipf_getinfo,
107ab25eeb5Syz #if SOLARIS2 >= 10
108ab25eeb5Syz 	nulldev,
109ab25eeb5Syz #else
110ab25eeb5Syz 	ipf_identify,
111ab25eeb5Syz #endif
112ab25eeb5Syz 	nulldev,
113ab25eeb5Syz 	ipf_attach,
114ab25eeb5Syz 	ipf_detach,
115ab25eeb5Syz 	nodev,		/* reset */
116ab25eeb5Syz 	&ipf_cb_ops,
117ab25eeb5Syz 	(struct bus_ops *)0
118ab25eeb5Syz };
119ab25eeb5Syz 
120ab25eeb5Syz extern struct mod_ops mod_driverops;
121ab25eeb5Syz static struct modldrv iplmod = {
122ab25eeb5Syz 	&mod_driverops, IPL_VERSION, &ipf_ops };
123ab25eeb5Syz static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
124ab25eeb5Syz 
125ab25eeb5Syz #if SOLARIS2 >= 6
126ab25eeb5Syz static	size_t	hdrsizes[57][2] = {
127ab25eeb5Syz 	{ 0, 0 },
128ab25eeb5Syz 	{ IFT_OTHER, 0 },
129ab25eeb5Syz 	{ IFT_1822, 0 },
130ab25eeb5Syz 	{ IFT_HDH1822, 0 },
131ab25eeb5Syz 	{ IFT_X25DDN, 0 },
132ab25eeb5Syz 	{ IFT_X25, 0 },
133ab25eeb5Syz 	{ IFT_ETHER, 14 },
134ab25eeb5Syz 	{ IFT_ISO88023, 0 },
135ab25eeb5Syz 	{ IFT_ISO88024, 0 },
136ab25eeb5Syz 	{ IFT_ISO88025, 0 },
137ab25eeb5Syz 	{ IFT_ISO88026, 0 },
138ab25eeb5Syz 	{ IFT_STARLAN, 0 },
139ab25eeb5Syz 	{ IFT_P10, 0 },
140ab25eeb5Syz 	{ IFT_P80, 0 },
141ab25eeb5Syz 	{ IFT_HY, 0 },
142ab25eeb5Syz 	{ IFT_FDDI, 24 },
143ab25eeb5Syz 	{ IFT_LAPB, 0 },
144ab25eeb5Syz 	{ IFT_SDLC, 0 },
145ab25eeb5Syz 	{ IFT_T1, 0 },
146ab25eeb5Syz 	{ IFT_CEPT, 0 },
147ab25eeb5Syz 	{ IFT_ISDNBASIC, 0 },
148ab25eeb5Syz 	{ IFT_ISDNPRIMARY, 0 },
149ab25eeb5Syz 	{ IFT_PTPSERIAL, 0 },
150ab25eeb5Syz 	{ IFT_PPP, 0 },
151ab25eeb5Syz 	{ IFT_LOOP, 0 },
152ab25eeb5Syz 	{ IFT_EON, 0 },
153ab25eeb5Syz 	{ IFT_XETHER, 0 },
154ab25eeb5Syz 	{ IFT_NSIP, 0 },
155ab25eeb5Syz 	{ IFT_SLIP, 0 },
156ab25eeb5Syz 	{ IFT_ULTRA, 0 },
157ab25eeb5Syz 	{ IFT_DS3, 0 },
158ab25eeb5Syz 	{ IFT_SIP, 0 },
159ab25eeb5Syz 	{ IFT_FRELAY, 0 },
160ab25eeb5Syz 	{ IFT_RS232, 0 },
161ab25eeb5Syz 	{ IFT_PARA, 0 },
162ab25eeb5Syz 	{ IFT_ARCNET, 0 },
163ab25eeb5Syz 	{ IFT_ARCNETPLUS, 0 },
164ab25eeb5Syz 	{ IFT_ATM, 0 },
165ab25eeb5Syz 	{ IFT_MIOX25, 0 },
166ab25eeb5Syz 	{ IFT_SONET, 0 },
167ab25eeb5Syz 	{ IFT_X25PLE, 0 },
168ab25eeb5Syz 	{ IFT_ISO88022LLC, 0 },
169ab25eeb5Syz 	{ IFT_LOCALTALK, 0 },
170ab25eeb5Syz 	{ IFT_SMDSDXI, 0 },
171ab25eeb5Syz 	{ IFT_FRELAYDCE, 0 },
172ab25eeb5Syz 	{ IFT_V35, 0 },
173ab25eeb5Syz 	{ IFT_HSSI, 0 },
174ab25eeb5Syz 	{ IFT_HIPPI, 0 },
175ab25eeb5Syz 	{ IFT_MODEM, 0 },
176ab25eeb5Syz 	{ IFT_AAL5, 0 },
177ab25eeb5Syz 	{ IFT_SONETPATH, 0 },
178ab25eeb5Syz 	{ IFT_SONETVT, 0 },
179ab25eeb5Syz 	{ IFT_SMDSICIP, 0 },
180ab25eeb5Syz 	{ IFT_PROPVIRTUAL, 0 },
181ab25eeb5Syz 	{ IFT_PROPMUX, 0 },
182ab25eeb5Syz };
183ab25eeb5Syz #endif /* SOLARIS2 >= 6 */
184ab25eeb5Syz 
185*f4b3ec61Sdh dev_info_t *ipf_dev_info = NULL;
186ab25eeb5Syz 
187ab25eeb5Syz static const filter_kstats_t ipf_kstat_tmp = {
188ab25eeb5Syz 	{ "pass",			KSTAT_DATA_ULONG },
189ab25eeb5Syz 	{ "block",			KSTAT_DATA_ULONG },
190ab25eeb5Syz 	{ "nomatch",			KSTAT_DATA_ULONG },
191ab25eeb5Syz 	{ "short",			KSTAT_DATA_ULONG },
192ab25eeb5Syz 	{ "pass, logged",		KSTAT_DATA_ULONG },
193ab25eeb5Syz 	{ "block, logged",		KSTAT_DATA_ULONG },
194ab25eeb5Syz 	{ "nomatch, logged",		KSTAT_DATA_ULONG },
195ab25eeb5Syz 	{ "logged",			KSTAT_DATA_ULONG },
196ab25eeb5Syz 	{ "skip",			KSTAT_DATA_ULONG },
197ab25eeb5Syz 	{ "return sent",		KSTAT_DATA_ULONG },
198ab25eeb5Syz 	{ "acct",			KSTAT_DATA_ULONG },
199ab25eeb5Syz 	{ "bad frag state alloc",	KSTAT_DATA_ULONG },
200ab25eeb5Syz 	{ "new frag state kept",	KSTAT_DATA_ULONG },
201ab25eeb5Syz 	{ "new frag state compl. pkt",	KSTAT_DATA_ULONG },
202ab25eeb5Syz 	{ "bad pkt state alloc",	KSTAT_DATA_ULONG },
203ab25eeb5Syz 	{ "new pkt kept state",		KSTAT_DATA_ULONG },
204ab25eeb5Syz 	{ "cachehit",			KSTAT_DATA_ULONG },
205ab25eeb5Syz 	{ "tcp cksum bad",		KSTAT_DATA_ULONG },
206ab25eeb5Syz 	{{ "pullup ok",			KSTAT_DATA_ULONG },
207ab25eeb5Syz 	{ "pullup nok",			KSTAT_DATA_ULONG }},
208ab25eeb5Syz 	{ "src != route",		KSTAT_DATA_ULONG },
209ab25eeb5Syz 	{ "ttl invalid",		KSTAT_DATA_ULONG },
210ab25eeb5Syz 	{ "bad ip pkt",			KSTAT_DATA_ULONG },
211ab25eeb5Syz 	{ "ipv6 pkt",			KSTAT_DATA_ULONG },
212ab25eeb5Syz 	{ "dropped:pps ceiling",	KSTAT_DATA_ULONG },
213ab25eeb5Syz 	{ "ip upd. fail",		KSTAT_DATA_ULONG }
214ab25eeb5Syz };
215ab25eeb5Syz 
216381a2a9aSdr 
217ab25eeb5Syz static int	ipf_kstat_update(kstat_t *ksp, int rwflag);
218ab25eeb5Syz 
219ab25eeb5Syz static void
220*f4b3ec61Sdh ipf_kstat_init(ipf_stack_t *ifs, netstackid_t stackid)
221ab25eeb5Syz {
222ab25eeb5Syz 	int 	i;
223ab25eeb5Syz 
224ab25eeb5Syz 	for (i = 0; i < 2; i++) {
225*f4b3ec61Sdh 		ifs->ifs_kstatp[i] = kstat_create_netstack("ipf", 0,
226ab25eeb5Syz 			(i==0)?"inbound":"outbound",
227ab25eeb5Syz 			"net",
228ab25eeb5Syz 			KSTAT_TYPE_NAMED,
229ab25eeb5Syz 			sizeof (filter_kstats_t) / sizeof (kstat_named_t),
230*f4b3ec61Sdh 			0, stackid);
231*f4b3ec61Sdh 		if (ifs->ifs_kstatp[i] != NULL) {
232*f4b3ec61Sdh 			bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[i]->ks_data,
233ab25eeb5Syz 				sizeof (filter_kstats_t));
234*f4b3ec61Sdh 			ifs->ifs_kstatp[i]->ks_update = ipf_kstat_update;
235*f4b3ec61Sdh 			ifs->ifs_kstatp[i]->ks_private = &ifs->ifs_frstats[i];
236*f4b3ec61Sdh 			kstat_install(ifs->ifs_kstatp[i]);
237ab25eeb5Syz 		}
238ab25eeb5Syz 	}
239ab25eeb5Syz 
240ab25eeb5Syz #ifdef	IPFDEBUG
241ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init() installed 0x%x, 0x%x",
242*f4b3ec61Sdh 		ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
243ab25eeb5Syz #endif
244ab25eeb5Syz }
245ab25eeb5Syz 
246ab25eeb5Syz static void
247*f4b3ec61Sdh ipf_kstat_fini(ipf_stack_t *ifs, netstackid_t stackid)
248ab25eeb5Syz {
249ab25eeb5Syz 	int i;
250*f4b3ec61Sdh 
251ab25eeb5Syz 	for (i = 0; i < 2; i++) {
252*f4b3ec61Sdh 		if (ifs->ifs_kstatp[i] != NULL) {
253*f4b3ec61Sdh 			kstat_delete_netstack(ifs->ifs_kstatp[i], stackid);
254*f4b3ec61Sdh 			ifs->ifs_kstatp[i] = NULL;
255ab25eeb5Syz 		}
256ab25eeb5Syz 	}
257ab25eeb5Syz }
258ab25eeb5Syz 
259ab25eeb5Syz static int
260ab25eeb5Syz ipf_kstat_update(kstat_t *ksp, int rwflag)
261ab25eeb5Syz {
262ab25eeb5Syz 	filter_kstats_t	*fkp;
263ab25eeb5Syz 	filterstats_t	*fsp;
264ab25eeb5Syz 
265*f4b3ec61Sdh 	if (ksp == NULL || ksp->ks_data == NULL)
266*f4b3ec61Sdh 		return (EIO);
267*f4b3ec61Sdh 
268ab25eeb5Syz 	if (rwflag == KSTAT_WRITE)
269ab25eeb5Syz 		return (EACCES);
270ab25eeb5Syz 
271ab25eeb5Syz 	fkp = ksp->ks_data;
272ab25eeb5Syz 	fsp = ksp->ks_private;
273ab25eeb5Syz 
274ab25eeb5Syz 	fkp->fks_pass.value.ul		= fsp->fr_pass;
275ab25eeb5Syz 	fkp->fks_block.value.ul		= fsp->fr_block;
276ab25eeb5Syz 	fkp->fks_nom.value.ul		= fsp->fr_nom;
277ab25eeb5Syz 	fkp->fks_short.value.ul		= fsp->fr_short;
278ab25eeb5Syz 	fkp->fks_ppkl.value.ul		= fsp->fr_ppkl;
279ab25eeb5Syz 	fkp->fks_bpkl.value.ul		= fsp->fr_bpkl;
280ab25eeb5Syz 	fkp->fks_npkl.value.ul		= fsp->fr_npkl;
281ab25eeb5Syz 	fkp->fks_pkl.value.ul		= fsp->fr_pkl;
282ab25eeb5Syz 	fkp->fks_skip.value.ul		= fsp->fr_skip;
283ab25eeb5Syz 	fkp->fks_ret.value.ul		= fsp->fr_ret;
284ab25eeb5Syz 	fkp->fks_acct.value.ul		= fsp->fr_acct;
285ab25eeb5Syz 	fkp->fks_bnfr.value.ul		= fsp->fr_bnfr;
286ab25eeb5Syz 	fkp->fks_nfr.value.ul		= fsp->fr_nfr;
287ab25eeb5Syz 	fkp->fks_cfr.value.ul		= fsp->fr_cfr;
288ab25eeb5Syz 	fkp->fks_bads.value.ul		= fsp->fr_bads;
289ab25eeb5Syz 	fkp->fks_ads.value.ul		= fsp->fr_ads;
290ab25eeb5Syz 	fkp->fks_chit.value.ul		= fsp->fr_chit;
291ab25eeb5Syz 	fkp->fks_tcpbad.value.ul 	= fsp->fr_tcpbad;
292ab25eeb5Syz 	fkp->fks_pull[0].value.ul 	= fsp->fr_pull[0];
293ab25eeb5Syz 	fkp->fks_pull[1].value.ul 	= fsp->fr_pull[1];
294ab25eeb5Syz 	fkp->fks_badsrc.value.ul 	= fsp->fr_badsrc;
295ab25eeb5Syz 	fkp->fks_badttl.value.ul 	= fsp->fr_badttl;
296ab25eeb5Syz 	fkp->fks_bad.value.ul		= fsp->fr_bad;
297ab25eeb5Syz 	fkp->fks_ipv6.value.ul		= fsp->fr_ipv6;
298ab25eeb5Syz 	fkp->fks_ppshit.value.ul 	= fsp->fr_ppshit;
299ab25eeb5Syz 	fkp->fks_ipud.value.ul		= fsp->fr_ipud;
300ab25eeb5Syz 
301ab25eeb5Syz 	return (0);
302ab25eeb5Syz }
303ab25eeb5Syz 
304ab25eeb5Syz int _init()
305ab25eeb5Syz {
306ab25eeb5Syz 	int ipfinst;
307ab25eeb5Syz 
308ab25eeb5Syz 	ipfinst = mod_install(&modlink1);
309ab25eeb5Syz #ifdef	IPFDEBUG
310ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
311ab25eeb5Syz #endif
312ab25eeb5Syz 	return ipfinst;
313ab25eeb5Syz }
314ab25eeb5Syz 
315ab25eeb5Syz 
316ab25eeb5Syz int _fini(void)
317ab25eeb5Syz {
318ab25eeb5Syz 	int ipfinst;
319ab25eeb5Syz 
320ab25eeb5Syz 	ipfinst = mod_remove(&modlink1);
321ab25eeb5Syz #ifdef	IPFDEBUG
322ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
323ab25eeb5Syz #endif
324ab25eeb5Syz 	return ipfinst;
325ab25eeb5Syz }
326ab25eeb5Syz 
327ab25eeb5Syz 
328ab25eeb5Syz int _info(modinfop)
329ab25eeb5Syz struct modinfo *modinfop;
330ab25eeb5Syz {
331ab25eeb5Syz 	int ipfinst;
332ab25eeb5Syz 
333ab25eeb5Syz 	ipfinst = mod_info(&modlink1, modinfop);
334ab25eeb5Syz #ifdef	IPFDEBUG
335ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst);
336ab25eeb5Syz #endif
337ab25eeb5Syz 	return ipfinst;
338ab25eeb5Syz }
339ab25eeb5Syz 
340ab25eeb5Syz 
341ab25eeb5Syz #if SOLARIS2 < 10
342ab25eeb5Syz static int ipf_identify(dip)
343ab25eeb5Syz dev_info_t *dip;
344ab25eeb5Syz {
345ab25eeb5Syz # ifdef	IPFDEBUG
346ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
347ab25eeb5Syz # endif
348ab25eeb5Syz 	if (strcmp(ddi_get_name(dip), "ipf") == 0)
349ab25eeb5Syz 		return (DDI_IDENTIFIED);
350ab25eeb5Syz 	return (DDI_NOT_IDENTIFIED);
351ab25eeb5Syz }
352ab25eeb5Syz #endif
353ab25eeb5Syz 
354*f4b3ec61Sdh /*
355*f4b3ec61Sdh  * Initialize things for IPF for each stack instance
356*f4b3ec61Sdh  */
357*f4b3ec61Sdh static void *
358*f4b3ec61Sdh ipf_stack_init(netstackid_t stackid, netstack_t *ns)
359*f4b3ec61Sdh {
360*f4b3ec61Sdh 	ipf_stack_t	*ifs;
361*f4b3ec61Sdh 
362*f4b3ec61Sdh #ifdef NS_DEBUG
363*f4b3ec61Sdh 	(void) printf("ipf_stack_init(%d)\n", stackid);
364*f4b3ec61Sdh #endif
365*f4b3ec61Sdh 
366*f4b3ec61Sdh 	KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs));
367*f4b3ec61Sdh 	bzero(ifs, sizeof (*ifs));
368*f4b3ec61Sdh 
369*f4b3ec61Sdh 	ifs->ifs_netstack = ns;
370*f4b3ec61Sdh 
371*f4b3ec61Sdh 	ifs->ifs_hook4_physical_in	= B_FALSE;
372*f4b3ec61Sdh 	ifs->ifs_hook4_physical_out	= B_FALSE;
373*f4b3ec61Sdh 	ifs->ifs_hook4_nic_events	= B_FALSE;
374*f4b3ec61Sdh 	ifs->ifs_hook4_loopback_in	= B_FALSE;
375*f4b3ec61Sdh 	ifs->ifs_hook4_loopback_out	= B_FALSE;
376*f4b3ec61Sdh 	ifs->ifs_hook6_physical_in	= B_FALSE;
377*f4b3ec61Sdh 	ifs->ifs_hook6_physical_out	= B_FALSE;
378*f4b3ec61Sdh 	ifs->ifs_hook6_nic_events	= B_FALSE;
379*f4b3ec61Sdh 	ifs->ifs_hook6_loopback_in	= B_FALSE;
380*f4b3ec61Sdh 	ifs->ifs_hook6_loopback_out	= B_FALSE;
381*f4b3ec61Sdh 
382*f4b3ec61Sdh 	/*
383*f4b3ec61Sdh 	 * Initialize mutex's
384*f4b3ec61Sdh 	 */
385*f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
386*f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
387*f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
388*f4b3ec61Sdh #ifdef KERNEL
389*f4b3ec61Sdh 	ipf_kstat_init(ifs, stackid);
390*f4b3ec61Sdh #endif
391*f4b3ec61Sdh 
392*f4b3ec61Sdh 	/*
393*f4b3ec61Sdh 	 * Lock people out while we set things up.
394*f4b3ec61Sdh 	 */
395*f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_global);
396*f4b3ec61Sdh 	ipftuneable_alloc(ifs);
397*f4b3ec61Sdh 	ifs->ifs_fr_timer_id = timeout(fr_slowtimer, (void *)ifs,
398*f4b3ec61Sdh 	    drv_usectohz(500000));
399*f4b3ec61Sdh 
400*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
401*f4b3ec61Sdh 
402*f4b3ec61Sdh 	cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
403*f4b3ec61Sdh 	return (ifs);
404*f4b3ec61Sdh }
405*f4b3ec61Sdh 
406*f4b3ec61Sdh static int ipf_detach_check_zone(ipf_stack_t *ifs)
407*f4b3ec61Sdh {
408*f4b3ec61Sdh 	/*
409*f4b3ec61Sdh 	 * Make sure we're the only one's modifying things.  With
410*f4b3ec61Sdh 	 * this lock others should just fall out of the loop.
411*f4b3ec61Sdh 	 */
412*f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_global);
413*f4b3ec61Sdh 	if (ifs->ifs_fr_running == 1) {
414*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
415*f4b3ec61Sdh 		return (-1);
416*f4b3ec61Sdh 	}
417*f4b3ec61Sdh 
418*f4b3ec61Sdh 	/*
419*f4b3ec61Sdh 	 * Make sure there is no active filter rule.
420*f4b3ec61Sdh 	 */
421*f4b3ec61Sdh 	if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
422*f4b3ec61Sdh 	    ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
423*f4b3ec61Sdh 	    ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
424*f4b3ec61Sdh 	    ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
425*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
426*f4b3ec61Sdh 		return (-1);
427*f4b3ec61Sdh 	}
428*f4b3ec61Sdh 
429*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
430*f4b3ec61Sdh 
431*f4b3ec61Sdh 	return (0);
432*f4b3ec61Sdh }
433*f4b3ec61Sdh 
434*f4b3ec61Sdh static int ipf_detach_check_all()
435*f4b3ec61Sdh {
436*f4b3ec61Sdh 	netstack_handle_t nh;
437*f4b3ec61Sdh 	netstack_t *ns;
438*f4b3ec61Sdh 	int ret;
439*f4b3ec61Sdh 
440*f4b3ec61Sdh 	netstack_next_init(&nh);
441*f4b3ec61Sdh 	while ((ns = netstack_next(&nh)) != NULL) {
442*f4b3ec61Sdh 		ret = ipf_detach_check_zone(ns->netstack_ipf);
443*f4b3ec61Sdh 		netstack_rele(ns);
444*f4b3ec61Sdh 		if (ret != 0) {
445*f4b3ec61Sdh 			netstack_next_fini(&nh);
446*f4b3ec61Sdh 			return (-1);
447*f4b3ec61Sdh 		}
448*f4b3ec61Sdh 	}
449*f4b3ec61Sdh 
450*f4b3ec61Sdh 	netstack_next_fini(&nh);
451*f4b3ec61Sdh 	return (0);
452*f4b3ec61Sdh }
453*f4b3ec61Sdh 
454*f4b3ec61Sdh /*
455*f4b3ec61Sdh  * Destroy things for ipf for one stack.
456*f4b3ec61Sdh  */
457*f4b3ec61Sdh /* ARGSUSED */
458*f4b3ec61Sdh static void
459*f4b3ec61Sdh ipf_stack_fini(netstackid_t stackid, void *arg)
460*f4b3ec61Sdh {
461*f4b3ec61Sdh 	ipf_stack_t *ifs = (ipf_stack_t *)arg;
462*f4b3ec61Sdh 
463*f4b3ec61Sdh #ifdef NS_DEBUG
464*f4b3ec61Sdh 	(void) printf("ipf_stack_destroy(%p, stackid %d)\n",
465*f4b3ec61Sdh 	    (void *)ifs, stackid);
466*f4b3ec61Sdh #endif
467*f4b3ec61Sdh 
468*f4b3ec61Sdh 	/*
469*f4b3ec61Sdh 	 * Make sure we're the only one's modifying things.  With
470*f4b3ec61Sdh 	 * this lock others should just fall out of the loop.
471*f4b3ec61Sdh 	 */
472*f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_global);
473*f4b3ec61Sdh 	if (ifs->ifs_fr_running == -2) {
474*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
475*f4b3ec61Sdh 		return;
476*f4b3ec61Sdh 	}
477*f4b3ec61Sdh 	ifs->ifs_fr_running = -2;
478*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
479*f4b3ec61Sdh 
480*f4b3ec61Sdh #ifdef KERNEL
481*f4b3ec61Sdh 	ipf_kstat_fini(ifs, stackid);
482*f4b3ec61Sdh #endif
483*f4b3ec61Sdh 	if (ifs->ifs_fr_timer_id != 0) {
484*f4b3ec61Sdh 		(void) untimeout(ifs->ifs_fr_timer_id);
485*f4b3ec61Sdh 		ifs->ifs_fr_timer_id = 0;
486*f4b3ec61Sdh 	}
487*f4b3ec61Sdh 
488*f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_global);
489*f4b3ec61Sdh 	if (ipldetach(ifs) != 0) {
490*f4b3ec61Sdh 		printf("ipf_stack_fini: ipldetach failed\n");
491*f4b3ec61Sdh 	}
492*f4b3ec61Sdh 
493*f4b3ec61Sdh 	ipftuneable_free(ifs);
494*f4b3ec61Sdh 
495*f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
496*f4b3ec61Sdh 	RW_DESTROY(&ifs->ifs_ipf_mutex);
497*f4b3ec61Sdh 	RW_DESTROY(&ifs->ifs_ipf_frcache);
498*f4b3ec61Sdh 	RW_DESTROY(&ifs->ifs_ipf_global);
499*f4b3ec61Sdh 
500*f4b3ec61Sdh 	KFREE(ifs);
501*f4b3ec61Sdh }
502ab25eeb5Syz 
503ab25eeb5Syz static int ipf_attach(dip, cmd)
504ab25eeb5Syz dev_info_t *dip;
505ab25eeb5Syz ddi_attach_cmd_t cmd;
506ab25eeb5Syz {
507ab25eeb5Syz 	char *s;
508ab25eeb5Syz 	int i;
509ab25eeb5Syz 	int instance;
510ab25eeb5Syz 
511ab25eeb5Syz #ifdef	IPFDEBUG
512ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
513ab25eeb5Syz #endif
514ab25eeb5Syz 
515ab25eeb5Syz 	switch (cmd)
516ab25eeb5Syz 	{
517ab25eeb5Syz 	case DDI_ATTACH:
518ab25eeb5Syz 		instance = ddi_get_instance(dip);
519ab25eeb5Syz 		/* Only one instance of ipf (instance 0) can be attached. */
520ab25eeb5Syz 		if (instance > 0)
521ab25eeb5Syz 			return DDI_FAILURE;
522ab25eeb5Syz 
523ab25eeb5Syz #ifdef	IPFDEBUG
524ab25eeb5Syz 		cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
525ab25eeb5Syz #endif
526ab25eeb5Syz 
527*f4b3ec61Sdh 		(void) ipf_property_g_update(dip);
528ab25eeb5Syz 
529ab25eeb5Syz 		for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
530ab25eeb5Syz 			s = strrchr(s, '/');
531ab25eeb5Syz 			if (s == NULL)
532ab25eeb5Syz 				continue;
533ab25eeb5Syz 			s++;
534ab25eeb5Syz 			if (ddi_create_minor_node(dip, s, S_IFCHR, i,
535ab25eeb5Syz 						  DDI_PSEUDO, 0) ==
536ab25eeb5Syz 			    DDI_FAILURE) {
537ab25eeb5Syz 				ddi_remove_minor_node(dip, NULL);
538ab25eeb5Syz 				goto attach_failed;
539ab25eeb5Syz 			}
540ab25eeb5Syz 		}
541ab25eeb5Syz 
542ab25eeb5Syz 		ipf_dev_info = dip;
543*f4b3ec61Sdh 		netstack_register(NS_IPF, ipf_stack_init, NULL,
544*f4b3ec61Sdh 		    ipf_stack_fini);
545ab25eeb5Syz 		return DDI_SUCCESS;
546ab25eeb5Syz 		/* NOTREACHED */
547ab25eeb5Syz 	default:
548ab25eeb5Syz 		break;
549ab25eeb5Syz 	}
550ab25eeb5Syz 
551ab25eeb5Syz attach_failed:
552*f4b3ec61Sdh 	ddi_prop_remove_all(dip);
553ab25eeb5Syz 	return DDI_FAILURE;
554ab25eeb5Syz }
555ab25eeb5Syz 
556ab25eeb5Syz 
557ab25eeb5Syz static int ipf_detach(dip, cmd)
558ab25eeb5Syz dev_info_t *dip;
559ab25eeb5Syz ddi_detach_cmd_t cmd;
560ab25eeb5Syz {
561ab25eeb5Syz 	int i;
562ab25eeb5Syz 
563ab25eeb5Syz #ifdef	IPFDEBUG
564ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
565ab25eeb5Syz #endif
566ab25eeb5Syz 	switch (cmd) {
567ab25eeb5Syz 	case DDI_DETACH:
568*f4b3ec61Sdh 		if (ipf_detach_check_all() != 0)
569ab25eeb5Syz 			return DDI_FAILURE;
570ab25eeb5Syz 
571*f4b3ec61Sdh 		/* Undo what we did in ipf_attach, freeing resources
572ab25eeb5Syz 		 * and removing things we installed.  The system
573ab25eeb5Syz 		 * framework guarantees we are not active with this devinfo
574ab25eeb5Syz 		 * node in any other entry points at this time.
575ab25eeb5Syz 		 */
576ab25eeb5Syz 		ddi_prop_remove_all(dip);
577ab25eeb5Syz 		i = ddi_get_instance(dip);
578ab25eeb5Syz 		ddi_remove_minor_node(dip, NULL);
579ab25eeb5Syz 		if (i > 0) {
580ab25eeb5Syz 			cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
581ab25eeb5Syz 			return DDI_FAILURE;
582ab25eeb5Syz 		}
583ab25eeb5Syz 
584*f4b3ec61Sdh 		netstack_unregister(NS_IPF);
585*f4b3ec61Sdh 		return DDI_SUCCESS;
586*f4b3ec61Sdh 		/* NOTREACHED */
587ab25eeb5Syz 	default:
588ab25eeb5Syz 		break;
589ab25eeb5Syz 	}
590ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
591ab25eeb5Syz 	return DDI_FAILURE;
592ab25eeb5Syz }
593ab25eeb5Syz 
594ab25eeb5Syz 
595ab25eeb5Syz /*ARGSUSED*/
596ab25eeb5Syz static int ipf_getinfo(dip, infocmd, arg, result)
597ab25eeb5Syz dev_info_t *dip;
598ab25eeb5Syz ddi_info_cmd_t infocmd;
599ab25eeb5Syz void *arg, **result;
600ab25eeb5Syz {
601ab25eeb5Syz 	int error;
602ab25eeb5Syz 
603ab25eeb5Syz 	error = DDI_FAILURE;
604ab25eeb5Syz #ifdef	IPFDEBUG
605ab25eeb5Syz 	cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg);
606ab25eeb5Syz #endif
607ab25eeb5Syz 	switch (infocmd) {
608ab25eeb5Syz 	case DDI_INFO_DEVT2DEVINFO:
609ab25eeb5Syz 		*result = ipf_dev_info;
610ab25eeb5Syz 		error = DDI_SUCCESS;
611ab25eeb5Syz 		break;
612ab25eeb5Syz 	case DDI_INFO_DEVT2INSTANCE:
613ab25eeb5Syz 		*result = (void *)0;
614ab25eeb5Syz 		error = DDI_SUCCESS;
615ab25eeb5Syz 		break;
616ab25eeb5Syz 	default:
617ab25eeb5Syz 		break;
618ab25eeb5Syz 	}
619ab25eeb5Syz 	return (error);
620ab25eeb5Syz }
621ab25eeb5Syz 
622ab25eeb5Syz 
623ab25eeb5Syz /*
624ab25eeb5Syz  * Fetch configuration file values that have been entered into the ipf.conf
625ab25eeb5Syz  * driver file.
626ab25eeb5Syz  */
627*f4b3ec61Sdh static int ipf_property_g_update(dip)
628ab25eeb5Syz dev_info_t *dip;
629ab25eeb5Syz {
630ab25eeb5Syz #ifdef DDI_NO_AUTODETACH
631ab25eeb5Syz 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
632ab25eeb5Syz 				DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
633ab25eeb5Syz 		cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
634ab25eeb5Syz 		return DDI_FAILURE;
635ab25eeb5Syz 	}
636ab25eeb5Syz #else
637ab25eeb5Syz 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
638ab25eeb5Syz 				"ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
639ab25eeb5Syz 		cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
640ab25eeb5Syz 		return DDI_FAILURE;
641ab25eeb5Syz 	}
642ab25eeb5Syz #endif
643ab25eeb5Syz 
644*f4b3ec61Sdh 	return DDI_SUCCESS;
645*f4b3ec61Sdh }
646*f4b3ec61Sdh 
647*f4b3ec61Sdh int ipf_property_update(dip, ifs)
648*f4b3ec61Sdh dev_info_t *dip;
649*f4b3ec61Sdh ipf_stack_t *ifs;
650*f4b3ec61Sdh {
651*f4b3ec61Sdh 	ipftuneable_t *ipft;
652*f4b3ec61Sdh 	int64_t *i64p;
653*f4b3ec61Sdh 	char *name;
654*f4b3ec61Sdh 	u_int one;
655*f4b3ec61Sdh 	int *i32p;
656*f4b3ec61Sdh 	int err;
657*f4b3ec61Sdh 
658*f4b3ec61Sdh 	for (ipft = ifs->ifs_ipf_tuneables; (name = ipft->ipft_name) != NULL; ipft++) {
659ab25eeb5Syz 		one = 1;
660ab25eeb5Syz 		switch (ipft->ipft_sz)
661ab25eeb5Syz 		{
662ab25eeb5Syz 		case 4 :
663ab25eeb5Syz 			i32p = NULL;
664ab25eeb5Syz 			err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
665ab25eeb5Syz 							0, name, &i32p, &one);
666ab25eeb5Syz 			if (err == DDI_PROP_NOT_FOUND)
667ab25eeb5Syz 				continue;
668ab25eeb5Syz #ifdef	IPFDEBUG
669ab25eeb5Syz 			cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
670ab25eeb5Syz 				name, err);
671ab25eeb5Syz #endif
672ab25eeb5Syz 			if (err != DDI_PROP_SUCCESS)
673ab25eeb5Syz 				return err;
674ab25eeb5Syz 			if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max)
675ab25eeb5Syz 				*ipft->ipft_pint = *i32p;
676ab25eeb5Syz 			else
677ab25eeb5Syz 				err = DDI_PROP_CANNOT_DECODE;
678ab25eeb5Syz 			ddi_prop_free(i32p);
679ab25eeb5Syz 			break;
680ab25eeb5Syz 
681ab25eeb5Syz #if SOLARIS2 > 8
682ab25eeb5Syz 		case 8 :
683ab25eeb5Syz 			i64p = NULL;
684ab25eeb5Syz 			err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip,
685ab25eeb5Syz 							  0, name, &i64p, &one);
686ab25eeb5Syz 			if (err == DDI_PROP_NOT_FOUND)
687ab25eeb5Syz 				continue;
688ab25eeb5Syz # ifdef	IPFDEBUG
689ab25eeb5Syz 			cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n",
690ab25eeb5Syz 				name, err);
691ab25eeb5Syz # endif
692ab25eeb5Syz 			if (err != DDI_PROP_SUCCESS)
693ab25eeb5Syz 				return err;
694ab25eeb5Syz 			if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max)
695ab25eeb5Syz 				*ipft->ipft_pint = *i64p;
696ab25eeb5Syz 			else
697ab25eeb5Syz 				err = DDI_PROP_CANNOT_DECODE;
698ab25eeb5Syz 			ddi_prop_free(i64p);
699ab25eeb5Syz 			break;
700ab25eeb5Syz #endif
701ab25eeb5Syz 		default :
702ab25eeb5Syz 			break;
703ab25eeb5Syz 		}
704ab25eeb5Syz 		if (err != DDI_SUCCESS)
705ab25eeb5Syz 			break;
706ab25eeb5Syz 	}
707ab25eeb5Syz 	return err;
708ab25eeb5Syz }
709