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