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