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