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