xref: /onnv-gate/usr/src/uts/common/inet/ipf/solaris.c (revision 2958:98aa41c076f5)
12393Syz155240 /*
22393Syz155240  * Copyright (C) 1993-2001, 2003 by Darren Reed.
32393Syz155240  *
42393Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
52393Syz155240  *
62393Syz155240  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
72393Syz155240  * Use is subject to license terms.
82393Syz155240  */
92393Syz155240 /* #pragma ident   "@(#)solaris.c	1.12 6/5/96 (C) 1995 Darren Reed"*/
102393Syz155240 #pragma ident "@(#)$Id: solaris.c,v 2.73.2.6 2005/07/13 21:40:47 darrenr Exp $"
112393Syz155240 
122393Syz155240 #pragma ident	"%Z%%M%	%I%	%E% SMI"
132393Syz155240 
142393Syz155240 #include <sys/systm.h>
152393Syz155240 #include <sys/types.h>
162393Syz155240 #include <sys/param.h>
172393Syz155240 #include <sys/errno.h>
182393Syz155240 #include <sys/uio.h>
192393Syz155240 #include <sys/buf.h>
202393Syz155240 #include <sys/modctl.h>
212393Syz155240 #include <sys/open.h>
222393Syz155240 #include <sys/kmem.h>
232393Syz155240 #include <sys/conf.h>
242393Syz155240 #include <sys/cmn_err.h>
252393Syz155240 #include <sys/stat.h>
262393Syz155240 #include <sys/cred.h>
272393Syz155240 #include <sys/dditypes.h>
282393Syz155240 #include <sys/poll.h>
292393Syz155240 #include <sys/autoconf.h>
302393Syz155240 #include <sys/byteorder.h>
312393Syz155240 #include <sys/socket.h>
322393Syz155240 #include <sys/dlpi.h>
332393Syz155240 #include <sys/stropts.h>
342393Syz155240 #include <sys/kstat.h>
352393Syz155240 #include <sys/sockio.h>
36*2958Sdr146992 #include <sys/neti.h>
37*2958Sdr146992 #include <sys/hook.h>
382393Syz155240 #include <net/if.h>
392393Syz155240 #if SOLARIS2 >= 6
402393Syz155240 # include <net/if_types.h>
412393Syz155240 #endif
422393Syz155240 #include <net/af.h>
432393Syz155240 #include <net/route.h>
442393Syz155240 #include <netinet/in.h>
452393Syz155240 #include <netinet/in_systm.h>
462393Syz155240 #include <netinet/if_ether.h>
472393Syz155240 #include <netinet/ip.h>
482393Syz155240 #include <netinet/ip_var.h>
492393Syz155240 #include <netinet/tcp.h>
502393Syz155240 #include <netinet/udp.h>
512393Syz155240 #include <netinet/tcpip.h>
522393Syz155240 #include <netinet/ip_icmp.h>
532393Syz155240 #include <sys/ddi.h>
542393Syz155240 #include <sys/sunddi.h>
552393Syz155240 #include "netinet/ip_compat.h"
562393Syz155240 #include "netinet/ipl.h"
572393Syz155240 #include "netinet/ip_fil.h"
582393Syz155240 #include "netinet/ip_nat.h"
592393Syz155240 #include "netinet/ip_frag.h"
602393Syz155240 #include "netinet/ip_auth.h"
612393Syz155240 #include "netinet/ip_state.h"
622393Syz155240 
632393Syz155240 extern	struct	filterstats	frstats[];
642393Syz155240 extern	int	fr_running;
652393Syz155240 extern	int	fr_flags;
662393Syz155240 extern	int	iplwrite __P((dev_t, struct uio *, cred_t *));
672393Syz155240 
682393Syz155240 extern ipnat_t *nat_list;
692393Syz155240 
702393Syz155240 static	int	ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
712393Syz155240 				 void *, void **));
722393Syz155240 #if SOLARIS2 < 10
732393Syz155240 static	int	ipf_identify __P((dev_info_t *));
742393Syz155240 #endif
752393Syz155240 static	int	ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
762393Syz155240 static	int	ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
772393Syz155240 static	int	ipf_property_update __P((dev_info_t *));
782393Syz155240 static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
792393Syz155240 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
802393Syz155240 				    IPLOOKUP_NAME, NULL };
812393Syz155240 
822393Syz155240 
832393Syz155240 #if SOLARIS2 >= 7
842393Syz155240 extern	timeout_id_t	fr_timer_id;
852393Syz155240 #else
862393Syz155240 extern	int		fr_timer_id;
872393Syz155240 #endif
882393Syz155240 
892393Syz155240 static struct cb_ops ipf_cb_ops = {
902393Syz155240 	iplopen,
912393Syz155240 	iplclose,
922393Syz155240 	nodev,		/* strategy */
932393Syz155240 	nodev,		/* print */
942393Syz155240 	nodev,		/* dump */
952393Syz155240 	iplread,
962393Syz155240 	iplwrite,	/* write */
972393Syz155240 	iplioctl,	/* ioctl */
982393Syz155240 	nodev,		/* devmap */
992393Syz155240 	nodev,		/* mmap */
1002393Syz155240 	nodev,		/* segmap */
1012393Syz155240 	nochpoll,	/* poll */
1022393Syz155240 	ddi_prop_op,
1032393Syz155240 	NULL,
1042393Syz155240 	D_MTSAFE,
1052393Syz155240 #if SOLARIS2 > 4
1062393Syz155240 	CB_REV,
1072393Syz155240 	nodev,		/* aread */
1082393Syz155240 	nodev,		/* awrite */
1092393Syz155240 #endif
1102393Syz155240 };
1112393Syz155240 
1122393Syz155240 static struct dev_ops ipf_ops = {
1132393Syz155240 	DEVO_REV,
1142393Syz155240 	0,
1152393Syz155240 	ipf_getinfo,
1162393Syz155240 #if SOLARIS2 >= 10
1172393Syz155240 	nulldev,
1182393Syz155240 #else
1192393Syz155240 	ipf_identify,
1202393Syz155240 #endif
1212393Syz155240 	nulldev,
1222393Syz155240 	ipf_attach,
1232393Syz155240 	ipf_detach,
1242393Syz155240 	nodev,		/* reset */
1252393Syz155240 	&ipf_cb_ops,
1262393Syz155240 	(struct bus_ops *)0
1272393Syz155240 };
1282393Syz155240 
1292393Syz155240 extern struct mod_ops mod_driverops;
1302393Syz155240 static struct modldrv iplmod = {
1312393Syz155240 	&mod_driverops, IPL_VERSION, &ipf_ops };
1322393Syz155240 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
1332393Syz155240 
1342393Syz155240 #if SOLARIS2 >= 6
1352393Syz155240 static	size_t	hdrsizes[57][2] = {
1362393Syz155240 	{ 0, 0 },
1372393Syz155240 	{ IFT_OTHER, 0 },
1382393Syz155240 	{ IFT_1822, 0 },
1392393Syz155240 	{ IFT_HDH1822, 0 },
1402393Syz155240 	{ IFT_X25DDN, 0 },
1412393Syz155240 	{ IFT_X25, 0 },
1422393Syz155240 	{ IFT_ETHER, 14 },
1432393Syz155240 	{ IFT_ISO88023, 0 },
1442393Syz155240 	{ IFT_ISO88024, 0 },
1452393Syz155240 	{ IFT_ISO88025, 0 },
1462393Syz155240 	{ IFT_ISO88026, 0 },
1472393Syz155240 	{ IFT_STARLAN, 0 },
1482393Syz155240 	{ IFT_P10, 0 },
1492393Syz155240 	{ IFT_P80, 0 },
1502393Syz155240 	{ IFT_HY, 0 },
1512393Syz155240 	{ IFT_FDDI, 24 },
1522393Syz155240 	{ IFT_LAPB, 0 },
1532393Syz155240 	{ IFT_SDLC, 0 },
1542393Syz155240 	{ IFT_T1, 0 },
1552393Syz155240 	{ IFT_CEPT, 0 },
1562393Syz155240 	{ IFT_ISDNBASIC, 0 },
1572393Syz155240 	{ IFT_ISDNPRIMARY, 0 },
1582393Syz155240 	{ IFT_PTPSERIAL, 0 },
1592393Syz155240 	{ IFT_PPP, 0 },
1602393Syz155240 	{ IFT_LOOP, 0 },
1612393Syz155240 	{ IFT_EON, 0 },
1622393Syz155240 	{ IFT_XETHER, 0 },
1632393Syz155240 	{ IFT_NSIP, 0 },
1642393Syz155240 	{ IFT_SLIP, 0 },
1652393Syz155240 	{ IFT_ULTRA, 0 },
1662393Syz155240 	{ IFT_DS3, 0 },
1672393Syz155240 	{ IFT_SIP, 0 },
1682393Syz155240 	{ IFT_FRELAY, 0 },
1692393Syz155240 	{ IFT_RS232, 0 },
1702393Syz155240 	{ IFT_PARA, 0 },
1712393Syz155240 	{ IFT_ARCNET, 0 },
1722393Syz155240 	{ IFT_ARCNETPLUS, 0 },
1732393Syz155240 	{ IFT_ATM, 0 },
1742393Syz155240 	{ IFT_MIOX25, 0 },
1752393Syz155240 	{ IFT_SONET, 0 },
1762393Syz155240 	{ IFT_X25PLE, 0 },
1772393Syz155240 	{ IFT_ISO88022LLC, 0 },
1782393Syz155240 	{ IFT_LOCALTALK, 0 },
1792393Syz155240 	{ IFT_SMDSDXI, 0 },
1802393Syz155240 	{ IFT_FRELAYDCE, 0 },
1812393Syz155240 	{ IFT_V35, 0 },
1822393Syz155240 	{ IFT_HSSI, 0 },
1832393Syz155240 	{ IFT_HIPPI, 0 },
1842393Syz155240 	{ IFT_MODEM, 0 },
1852393Syz155240 	{ IFT_AAL5, 0 },
1862393Syz155240 	{ IFT_SONETPATH, 0 },
1872393Syz155240 	{ IFT_SONETVT, 0 },
1882393Syz155240 	{ IFT_SMDSICIP, 0 },
1892393Syz155240 	{ IFT_PROPVIRTUAL, 0 },
1902393Syz155240 	{ IFT_PROPMUX, 0 },
1912393Syz155240 };
1922393Syz155240 #endif /* SOLARIS2 >= 6 */
1932393Syz155240 
1942393Syz155240 static dev_info_t *ipf_dev_info = NULL;
1952393Syz155240 
1962393Syz155240 static const filter_kstats_t ipf_kstat_tmp = {
1972393Syz155240 	{ "pass",			KSTAT_DATA_ULONG },
1982393Syz155240 	{ "block",			KSTAT_DATA_ULONG },
1992393Syz155240 	{ "nomatch",			KSTAT_DATA_ULONG },
2002393Syz155240 	{ "short",			KSTAT_DATA_ULONG },
2012393Syz155240 	{ "pass, logged",		KSTAT_DATA_ULONG },
2022393Syz155240 	{ "block, logged",		KSTAT_DATA_ULONG },
2032393Syz155240 	{ "nomatch, logged",		KSTAT_DATA_ULONG },
2042393Syz155240 	{ "logged",			KSTAT_DATA_ULONG },
2052393Syz155240 	{ "skip",			KSTAT_DATA_ULONG },
2062393Syz155240 	{ "return sent",		KSTAT_DATA_ULONG },
2072393Syz155240 	{ "acct",			KSTAT_DATA_ULONG },
2082393Syz155240 	{ "bad frag state alloc",	KSTAT_DATA_ULONG },
2092393Syz155240 	{ "new frag state kept",	KSTAT_DATA_ULONG },
2102393Syz155240 	{ "new frag state compl. pkt",	KSTAT_DATA_ULONG },
2112393Syz155240 	{ "bad pkt state alloc",	KSTAT_DATA_ULONG },
2122393Syz155240 	{ "new pkt kept state",		KSTAT_DATA_ULONG },
2132393Syz155240 	{ "cachehit",			KSTAT_DATA_ULONG },
2142393Syz155240 	{ "tcp cksum bad",		KSTAT_DATA_ULONG },
2152393Syz155240 	{{ "pullup ok",			KSTAT_DATA_ULONG },
2162393Syz155240 	{ "pullup nok",			KSTAT_DATA_ULONG }},
2172393Syz155240 	{ "src != route",		KSTAT_DATA_ULONG },
2182393Syz155240 	{ "ttl invalid",		KSTAT_DATA_ULONG },
2192393Syz155240 	{ "bad ip pkt",			KSTAT_DATA_ULONG },
2202393Syz155240 	{ "ipv6 pkt",			KSTAT_DATA_ULONG },
2212393Syz155240 	{ "dropped:pps ceiling",	KSTAT_DATA_ULONG },
2222393Syz155240 	{ "ip upd. fail",		KSTAT_DATA_ULONG }
2232393Syz155240 };
2242393Syz155240 
225*2958Sdr146992 net_data_t ipf_ipv4;
226*2958Sdr146992 net_data_t ipf_ipv6;
227*2958Sdr146992 
2282393Syz155240 kstat_t		*ipf_kstatp[2] = {NULL, NULL};
2292393Syz155240 static int	ipf_kstat_update(kstat_t *ksp, int rwflag);
2302393Syz155240 
2312393Syz155240 static void
2322393Syz155240 ipf_kstat_init(void)
2332393Syz155240 {
2342393Syz155240 	int 	i;
2352393Syz155240 
2362393Syz155240 	for (i = 0; i < 2; i++) {
2372393Syz155240 		ipf_kstatp[i] = kstat_create("ipf", 0,
2382393Syz155240 			(i==0)?"inbound":"outbound",
2392393Syz155240 			"net",
2402393Syz155240 			KSTAT_TYPE_NAMED,
2412393Syz155240 			sizeof (filter_kstats_t) / sizeof (kstat_named_t),
2422393Syz155240 			0);
2432393Syz155240 		if (ipf_kstatp[i] != NULL) {
2442393Syz155240 			bcopy(&ipf_kstat_tmp, ipf_kstatp[i]->ks_data,
2452393Syz155240 				sizeof (filter_kstats_t));
2462393Syz155240 			ipf_kstatp[i]->ks_update = ipf_kstat_update;
2472393Syz155240 			ipf_kstatp[i]->ks_private = &frstats[i];
2482393Syz155240 			kstat_install(ipf_kstatp[i]);
2492393Syz155240 		}
2502393Syz155240 	}
2512393Syz155240 
2522393Syz155240 #ifdef	IPFDEBUG
2532393Syz155240 	cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init() installed 0x%x, 0x%x",
2542393Syz155240 		ipf_kstatp[0], ipf_kstatp[1]);
2552393Syz155240 #endif
2562393Syz155240 }
2572393Syz155240 
2582393Syz155240 static void
2592393Syz155240 ipf_kstat_fini(void)
2602393Syz155240 {
2612393Syz155240 	int i;
2622393Syz155240 	for (i = 0; i < 2; i++) {
2632393Syz155240 		if (ipf_kstatp[i] != NULL) {
2642393Syz155240 			kstat_delete(ipf_kstatp[i]);
2652393Syz155240 			ipf_kstatp[i] = NULL;
2662393Syz155240 		}
2672393Syz155240 	}
2682393Syz155240 }
2692393Syz155240 
2702393Syz155240 static int
2712393Syz155240 ipf_kstat_update(kstat_t *ksp, int rwflag)
2722393Syz155240 {
2732393Syz155240 	filter_kstats_t	*fkp;
2742393Syz155240 	filterstats_t	*fsp;
2752393Syz155240 
2762393Syz155240 	if (rwflag == KSTAT_WRITE)
2772393Syz155240 		return (EACCES);
2782393Syz155240 
2792393Syz155240 	fkp = ksp->ks_data;
2802393Syz155240 	fsp = ksp->ks_private;
2812393Syz155240 
2822393Syz155240 	fkp->fks_pass.value.ul		= fsp->fr_pass;
2832393Syz155240 	fkp->fks_block.value.ul		= fsp->fr_block;
2842393Syz155240 	fkp->fks_nom.value.ul		= fsp->fr_nom;
2852393Syz155240 	fkp->fks_short.value.ul		= fsp->fr_short;
2862393Syz155240 	fkp->fks_ppkl.value.ul		= fsp->fr_ppkl;
2872393Syz155240 	fkp->fks_bpkl.value.ul		= fsp->fr_bpkl;
2882393Syz155240 	fkp->fks_npkl.value.ul		= fsp->fr_npkl;
2892393Syz155240 	fkp->fks_pkl.value.ul		= fsp->fr_pkl;
2902393Syz155240 	fkp->fks_skip.value.ul		= fsp->fr_skip;
2912393Syz155240 	fkp->fks_ret.value.ul		= fsp->fr_ret;
2922393Syz155240 	fkp->fks_acct.value.ul		= fsp->fr_acct;
2932393Syz155240 	fkp->fks_bnfr.value.ul		= fsp->fr_bnfr;
2942393Syz155240 	fkp->fks_nfr.value.ul		= fsp->fr_nfr;
2952393Syz155240 	fkp->fks_cfr.value.ul		= fsp->fr_cfr;
2962393Syz155240 	fkp->fks_bads.value.ul		= fsp->fr_bads;
2972393Syz155240 	fkp->fks_ads.value.ul		= fsp->fr_ads;
2982393Syz155240 	fkp->fks_chit.value.ul		= fsp->fr_chit;
2992393Syz155240 	fkp->fks_tcpbad.value.ul 	= fsp->fr_tcpbad;
3002393Syz155240 	fkp->fks_pull[0].value.ul 	= fsp->fr_pull[0];
3012393Syz155240 	fkp->fks_pull[1].value.ul 	= fsp->fr_pull[1];
3022393Syz155240 	fkp->fks_badsrc.value.ul 	= fsp->fr_badsrc;
3032393Syz155240 	fkp->fks_badttl.value.ul 	= fsp->fr_badttl;
3042393Syz155240 	fkp->fks_bad.value.ul		= fsp->fr_bad;
3052393Syz155240 	fkp->fks_ipv6.value.ul		= fsp->fr_ipv6;
3062393Syz155240 	fkp->fks_ppshit.value.ul 	= fsp->fr_ppshit;
3072393Syz155240 	fkp->fks_ipud.value.ul		= fsp->fr_ipud;
3082393Syz155240 
3092393Syz155240 	return (0);
3102393Syz155240 }
3112393Syz155240 
3122393Syz155240 int _init()
3132393Syz155240 {
3142393Syz155240 	int ipfinst;
3152393Syz155240 
3162393Syz155240 	ipf_kstat_init();
317*2958Sdr146992 
3182393Syz155240 	ipfinst = mod_install(&modlink1);
319*2958Sdr146992 
3202393Syz155240 	if (ipfinst != 0)
3212393Syz155240 		ipf_kstat_fini();
3222393Syz155240 #ifdef	IPFDEBUG
3232393Syz155240 	cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
3242393Syz155240 #endif
3252393Syz155240 	return ipfinst;
3262393Syz155240 }
3272393Syz155240 
3282393Syz155240 
3292393Syz155240 int _fini(void)
3302393Syz155240 {
3312393Syz155240 	int ipfinst;
3322393Syz155240 
3332393Syz155240 	ipfinst = mod_remove(&modlink1);
3342393Syz155240 #ifdef	IPFDEBUG
3352393Syz155240 	cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
3362393Syz155240 #endif
3372393Syz155240 	if (ipfinst == 0)
3382393Syz155240 		ipf_kstat_fini();
339*2958Sdr146992 
3402393Syz155240 	return ipfinst;
3412393Syz155240 }
3422393Syz155240 
3432393Syz155240 
3442393Syz155240 int _info(modinfop)
3452393Syz155240 struct modinfo *modinfop;
3462393Syz155240 {
3472393Syz155240 	int ipfinst;
3482393Syz155240 
3492393Syz155240 	ipfinst = mod_info(&modlink1, modinfop);
3502393Syz155240 #ifdef	IPFDEBUG
3512393Syz155240 	cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst);
3522393Syz155240 #endif
3532393Syz155240 	return ipfinst;
3542393Syz155240 }
3552393Syz155240 
3562393Syz155240 
3572393Syz155240 #if SOLARIS2 < 10
3582393Syz155240 static int ipf_identify(dip)
3592393Syz155240 dev_info_t *dip;
3602393Syz155240 {
3612393Syz155240 # ifdef	IPFDEBUG
3622393Syz155240 	cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
3632393Syz155240 # endif
3642393Syz155240 	if (strcmp(ddi_get_name(dip), "ipf") == 0)
3652393Syz155240 		return (DDI_IDENTIFIED);
3662393Syz155240 	return (DDI_NOT_IDENTIFIED);
3672393Syz155240 }
3682393Syz155240 #endif
3692393Syz155240 
3702393Syz155240 
3712393Syz155240 static int ipf_attach(dip, cmd)
3722393Syz155240 dev_info_t *dip;
3732393Syz155240 ddi_attach_cmd_t cmd;
3742393Syz155240 {
3752393Syz155240 	char *s;
3762393Syz155240 	int i;
3772393Syz155240 	int instance;
3782393Syz155240 
3792393Syz155240 #ifdef	IPFDEBUG
3802393Syz155240 	cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
3812393Syz155240 #endif
3822393Syz155240 
3832393Syz155240 	switch (cmd)
3842393Syz155240 	{
3852393Syz155240 	case DDI_ATTACH:
3862393Syz155240 		instance = ddi_get_instance(dip);
3872393Syz155240 		/* Only one instance of ipf (instance 0) can be attached. */
3882393Syz155240 		if (instance > 0)
3892393Syz155240 			return DDI_FAILURE;
3902393Syz155240 		if (fr_running != 0)
3912393Syz155240 			return DDI_FAILURE;
3922393Syz155240 
3932393Syz155240 #ifdef	IPFDEBUG
3942393Syz155240 		cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
3952393Syz155240 #endif
3962393Syz155240 
3972393Syz155240 		(void) ipf_property_update(dip);
3982393Syz155240 
3992393Syz155240 		for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
4002393Syz155240 			s = strrchr(s, '/');
4012393Syz155240 			if (s == NULL)
4022393Syz155240 				continue;
4032393Syz155240 			s++;
4042393Syz155240 			if (ddi_create_minor_node(dip, s, S_IFCHR, i,
4052393Syz155240 						  DDI_PSEUDO, 0) ==
4062393Syz155240 			    DDI_FAILURE) {
4072393Syz155240 				ddi_remove_minor_node(dip, NULL);
4082393Syz155240 				goto attach_failed;
4092393Syz155240 			}
4102393Syz155240 		}
4112393Syz155240 
4122393Syz155240 		ipf_dev_info = dip;
4132393Syz155240 		/*
4142393Syz155240 		 * Initialize mutex's
4152393Syz155240 		 */
4162393Syz155240 		RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
4172393Syz155240 		RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
4182393Syz155240 		RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
4192393Syz155240 
4202393Syz155240 		/*
4212393Syz155240 		 * Lock people out while we set things up.
4222393Syz155240 		 */
4232393Syz155240 		WRITE_ENTER(&ipf_global);
4242393Syz155240 		if ((fr_running != 0) || (iplattach() == -1)) {
4252393Syz155240 			RWLOCK_EXIT(&ipf_global);
4262393Syz155240 			goto attach_failed;
4272393Syz155240 		}
4282393Syz155240 
4292393Syz155240 		fr_timer_id = timeout(fr_slowtimer, NULL,
4302393Syz155240 				      drv_usectohz(500000));
4312393Syz155240 
4322393Syz155240 		fr_running = 1;
4332393Syz155240 
4342393Syz155240 		RWLOCK_EXIT(&ipf_global);
4352393Syz155240 
4362393Syz155240 		cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
4372393Syz155240 
4382393Syz155240 		return DDI_SUCCESS;
4392393Syz155240 		/* NOTREACHED */
4402393Syz155240 	default:
4412393Syz155240 		break;
4422393Syz155240 	}
4432393Syz155240 
4442393Syz155240 attach_failed:
4452393Syz155240 #ifdef	IPFDEBUG
4462393Syz155240 	cmn_err(CE_NOTE, "IP Filter: failed to attach\n");
4472393Syz155240 #endif
4482393Syz155240 	/*
4492393Syz155240 	 * Use our own detach routine to toss
4502393Syz155240 	 * away any stuff we allocated above.
4512393Syz155240 	 */
4522393Syz155240 	(void) ipf_detach(dip, DDI_DETACH);
4532393Syz155240 	return DDI_FAILURE;
4542393Syz155240 }
4552393Syz155240 
4562393Syz155240 
4572393Syz155240 static int ipf_detach(dip, cmd)
4582393Syz155240 dev_info_t *dip;
4592393Syz155240 ddi_detach_cmd_t cmd;
4602393Syz155240 {
4612393Syz155240 	int i;
4622393Syz155240 
4632393Syz155240 #ifdef	IPFDEBUG
4642393Syz155240 	cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
4652393Syz155240 #endif
4662393Syz155240 	switch (cmd) {
4672393Syz155240 	case DDI_DETACH:
4682393Syz155240 		if (fr_refcnt != 0)
4692393Syz155240 			return DDI_FAILURE;
4702393Syz155240 
471*2958Sdr146992 		if (fr_running == -2)
4722393Syz155240 			break;
4732393Syz155240 		/*
4742393Syz155240 		 * Make sure we're the only one's modifying things.  With
4752393Syz155240 		 * this lock others should just fall out of the loop.
4762393Syz155240 		 */
4772393Syz155240 		WRITE_ENTER(&ipf_global);
4782393Syz155240 		if (fr_running <= 0) {
4792393Syz155240 			RWLOCK_EXIT(&ipf_global);
4802393Syz155240 			return DDI_FAILURE;
4812393Syz155240 		}
482*2958Sdr146992 		/*
483*2958Sdr146992 		 * Make sure there is no active filter rule.
484*2958Sdr146992 		 */
485*2958Sdr146992 		if (ipfilter[0][fr_active] || ipfilter[1][fr_active] ||
486*2958Sdr146992 		    ipfilter6[0][fr_active] || ipfilter6[1][fr_active]) {
487*2958Sdr146992 		    RWLOCK_EXIT(&ipf_global);
488*2958Sdr146992 			return DDI_FAILURE;
489*2958Sdr146992 		}
4902393Syz155240 		fr_running = -2;
4912393Syz155240 
4922393Syz155240 		RWLOCK_EXIT(&ipf_global);
4932393Syz155240 
4942393Syz155240 		if (fr_timer_id != 0) {
4952393Syz155240 			(void) untimeout(fr_timer_id);
4962393Syz155240 			fr_timer_id = 0;
4972393Syz155240 		}
4982393Syz155240 
4992393Syz155240 		/*
5002393Syz155240 		 * Undo what we did in ipf_attach, freeing resources
5012393Syz155240 		 * and removing things we installed.  The system
5022393Syz155240 		 * framework guarantees we are not active with this devinfo
5032393Syz155240 		 * node in any other entry points at this time.
5042393Syz155240 		 */
5052393Syz155240 		ddi_prop_remove_all(dip);
5062393Syz155240 		i = ddi_get_instance(dip);
5072393Syz155240 		ddi_remove_minor_node(dip, NULL);
5082393Syz155240 		if (i > 0) {
5092393Syz155240 			cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
5102393Syz155240 			return DDI_FAILURE;
5112393Syz155240 		}
5122393Syz155240 
5132393Syz155240 		WRITE_ENTER(&ipf_global);
5142393Syz155240 		if (!ipldetach()) {
5152393Syz155240 			RWLOCK_EXIT(&ipf_global);
5162393Syz155240 			RW_DESTROY(&ipf_mutex);
5172393Syz155240 			RW_DESTROY(&ipf_frcache);
5182393Syz155240 			RW_DESTROY(&ipf_global);
5192393Syz155240 			cmn_err(CE_CONT, "!%s detached.\n", ipfilter_version);
5202393Syz155240 			return (DDI_SUCCESS);
5212393Syz155240 		}
5222393Syz155240 		RWLOCK_EXIT(&ipf_global);
5232393Syz155240 		break;
5242393Syz155240 	default:
5252393Syz155240 		break;
5262393Syz155240 	}
5272393Syz155240 	cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
5282393Syz155240 	return DDI_FAILURE;
5292393Syz155240 }
5302393Syz155240 
5312393Syz155240 
5322393Syz155240 /*ARGSUSED*/
5332393Syz155240 static int ipf_getinfo(dip, infocmd, arg, result)
5342393Syz155240 dev_info_t *dip;
5352393Syz155240 ddi_info_cmd_t infocmd;
5362393Syz155240 void *arg, **result;
5372393Syz155240 {
5382393Syz155240 	int error;
5392393Syz155240 
5402393Syz155240 	if (fr_running <= 0)
5412393Syz155240 		return DDI_FAILURE;
5422393Syz155240 	error = DDI_FAILURE;
5432393Syz155240 #ifdef	IPFDEBUG
5442393Syz155240 	cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg);
5452393Syz155240 #endif
5462393Syz155240 	switch (infocmd) {
5472393Syz155240 	case DDI_INFO_DEVT2DEVINFO:
5482393Syz155240 		*result = ipf_dev_info;
5492393Syz155240 		error = DDI_SUCCESS;
5502393Syz155240 		break;
5512393Syz155240 	case DDI_INFO_DEVT2INSTANCE:
5522393Syz155240 		*result = (void *)0;
5532393Syz155240 		error = DDI_SUCCESS;
5542393Syz155240 		break;
5552393Syz155240 	default:
5562393Syz155240 		break;
5572393Syz155240 	}
5582393Syz155240 	return (error);
5592393Syz155240 }
5602393Syz155240 
5612393Syz155240 
5622393Syz155240 /*
5632393Syz155240  * Fetch configuration file values that have been entered into the ipf.conf
5642393Syz155240  * driver file.
5652393Syz155240  */
5662393Syz155240 static int ipf_property_update(dip)
5672393Syz155240 dev_info_t *dip;
5682393Syz155240 {
5692393Syz155240 	ipftuneable_t *ipft;
5702393Syz155240 	int64_t *i64p;
5712393Syz155240 	char *name;
5722393Syz155240 	u_int one;
5732393Syz155240 	int *i32p;
5742393Syz155240 	int err;
5752393Syz155240 
5762393Syz155240 #ifdef DDI_NO_AUTODETACH
5772393Syz155240 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
5782393Syz155240 				DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
5792393Syz155240 		cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
5802393Syz155240 		return DDI_FAILURE;
5812393Syz155240 	}
5822393Syz155240 #else
5832393Syz155240 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
5842393Syz155240 				"ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
5852393Syz155240 		cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
5862393Syz155240 		return DDI_FAILURE;
5872393Syz155240 	}
5882393Syz155240 #endif
5892393Syz155240 
5902393Syz155240 	err = DDI_SUCCESS;
5912393Syz155240 	ipft = ipf_tuneables;
5922393Syz155240 	for (ipft = ipf_tuneables; (name = ipft->ipft_name) != NULL; ipft++) {
5932393Syz155240 		one = 1;
5942393Syz155240 		switch (ipft->ipft_sz)
5952393Syz155240 		{
5962393Syz155240 		case 4 :
5972393Syz155240 			i32p = NULL;
5982393Syz155240 			err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
5992393Syz155240 							0, name, &i32p, &one);
6002393Syz155240 			if (err == DDI_PROP_NOT_FOUND)
6012393Syz155240 				continue;
6022393Syz155240 #ifdef	IPFDEBUG
6032393Syz155240 			cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
6042393Syz155240 				name, err);
6052393Syz155240 #endif
6062393Syz155240 			if (err != DDI_PROP_SUCCESS)
6072393Syz155240 				return err;
6082393Syz155240 			if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max)
6092393Syz155240 				*ipft->ipft_pint = *i32p;
6102393Syz155240 			else
6112393Syz155240 				err = DDI_PROP_CANNOT_DECODE;
6122393Syz155240 			ddi_prop_free(i32p);
6132393Syz155240 			break;
6142393Syz155240 
6152393Syz155240 #if SOLARIS2 > 8
6162393Syz155240 		case 8 :
6172393Syz155240 			i64p = NULL;
6182393Syz155240 			err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip,
6192393Syz155240 							  0, name, &i64p, &one);
6202393Syz155240 			if (err == DDI_PROP_NOT_FOUND)
6212393Syz155240 				continue;
6222393Syz155240 # ifdef	IPFDEBUG
6232393Syz155240 			cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n",
6242393Syz155240 				name, err);
6252393Syz155240 # endif
6262393Syz155240 			if (err != DDI_PROP_SUCCESS)
6272393Syz155240 				return err;
6282393Syz155240 			if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max)
6292393Syz155240 				*ipft->ipft_pint = *i64p;
6302393Syz155240 			else
6312393Syz155240 				err = DDI_PROP_CANNOT_DECODE;
6322393Syz155240 			ddi_prop_free(i64p);
6332393Syz155240 			break;
6342393Syz155240 #endif
6352393Syz155240 
6362393Syz155240 		default :
6372393Syz155240 			break;
6382393Syz155240 		}
6392393Syz155240 		if (err != DDI_SUCCESS)
6402393Syz155240 			break;
6412393Syz155240 	}
6422393Syz155240 
6432393Syz155240 	return err;
6442393Syz155240 }
645