xref: /illumos-gate/usr/src/uts/common/inet/ipf/solaris.c (revision 92a0208178405fef708b0283ffcaa02fbc3468ff)
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 /* #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 #include <sys/systm.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/errno.h>
16 #include <sys/uio.h>
17 #include <sys/buf.h>
18 #include <sys/modctl.h>
19 #include <sys/open.h>
20 #include <sys/kmem.h>
21 #include <sys/conf.h>
22 #include <sys/cmn_err.h>
23 #include <sys/stat.h>
24 #include <sys/cred.h>
25 #include <sys/dditypes.h>
26 #include <sys/poll.h>
27 #include <sys/autoconf.h>
28 #include <sys/byteorder.h>
29 #include <sys/socket.h>
30 #include <sys/dlpi.h>
31 #include <sys/stropts.h>
32 #include <sys/kstat.h>
33 #include <sys/sockio.h>
34 #include <sys/neti.h>
35 #include <sys/hook.h>
36 #include <net/if.h>
37 #if SOLARIS2 >= 6
38 # include <net/if_types.h>
39 #endif
40 #include <net/af.h>
41 #include <net/route.h>
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/if_ether.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip_var.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netinet/tcpip.h>
50 #include <netinet/ip_icmp.h>
51 #include <sys/ddi.h>
52 #include <sys/sunddi.h>
53 #include "netinet/ip_compat.h"
54 #include "netinet/ipl.h"
55 #include "netinet/ip_fil.h"
56 #include "netinet/ip_nat.h"
57 #include "netinet/ip_frag.h"
58 #include "netinet/ip_auth.h"
59 #include "netinet/ip_state.h"
60 #include "netinet/ipf_stack.h"
61 
62 extern	int	iplwrite __P((dev_t, struct uio *, cred_t *));
63 
64 static	int	ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
65 				 void *, void **));
66 #if SOLARIS2 < 10
67 static	int	ipf_identify __P((dev_info_t *));
68 #endif
69 static	int	ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
70 static	int	ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
71 static	void	*ipf_stack_create __P((const netid_t));
72 static	void	ipf_stack_destroy __P((const netid_t, void *));
73 static	int	ipf_property_g_update __P((dev_info_t *));
74 static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
75 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
76 				    IPLOOKUP_NAME, NULL };
77 
78 
79 static struct cb_ops ipf_cb_ops = {
80 	iplopen,
81 	iplclose,
82 	nodev,		/* strategy */
83 	nodev,		/* print */
84 	nodev,		/* dump */
85 	iplread,
86 	iplwrite,	/* write */
87 	iplioctl,	/* ioctl */
88 	nodev,		/* devmap */
89 	nodev,		/* mmap */
90 	nodev,		/* segmap */
91 	nochpoll,	/* poll */
92 	ddi_prop_op,
93 	NULL,
94 	D_MTSAFE,
95 #if SOLARIS2 > 4
96 	CB_REV,
97 	nodev,		/* aread */
98 	nodev,		/* awrite */
99 #endif
100 };
101 
102 static struct dev_ops ipf_ops = {
103 	DEVO_REV,
104 	0,
105 	ipf_getinfo,
106 #if SOLARIS2 >= 10
107 	nulldev,
108 #else
109 	ipf_identify,
110 #endif
111 	nulldev,
112 	ipf_attach,
113 	ipf_detach,
114 	nodev,		/* reset */
115 	&ipf_cb_ops,
116 	(struct bus_ops *)0
117 };
118 
119 
120 static net_instance_t *ipfncb = NULL;
121 static ipf_stack_t *ipf_stacks = NULL;
122 static kmutex_t ipf_stack_lock;
123 extern struct mod_ops mod_driverops;
124 static struct modldrv iplmod = {
125 	&mod_driverops, IPL_VERSION, &ipf_ops };
126 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL };
127 
128 #if SOLARIS2 >= 6
129 static	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 
188 dev_info_t *ipf_dev_info = NULL;
189 
190 static 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 
220 static int	ipf_kstat_update(kstat_t *ksp, int rwflag);
221 
222 static void
223 ipf_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 
254 static void
255 ipf_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 
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 (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 
313 int _init()
314 {
315 	int ipfinst;
316 
317 	ipfinst = mod_install(&modlink1);
318 #ifdef	IPFDEBUG
319 	cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
320 #endif
321 	mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
322 	return ipfinst;
323 }
324 
325 
326 int _fini(void)
327 {
328 	int ipfinst;
329 
330 	ipfinst = mod_remove(&modlink1);
331 #ifdef	IPFDEBUG
332 	cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst);
333 #endif
334 	return ipfinst;
335 }
336 
337 
338 int _info(modinfop)
339 struct modinfo *modinfop;
340 {
341 	int ipfinst;
342 
343 	ipfinst = mod_info(&modlink1, modinfop);
344 #ifdef	IPFDEBUG
345 	cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
346 #endif
347 	return ipfinst;
348 }
349 
350 
351 #if SOLARIS2 < 10
352 static int ipf_identify(dip)
353 dev_info_t *dip;
354 {
355 # ifdef	IPFDEBUG
356 	cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
357 # endif
358 	if (strcmp(ddi_get_name(dip), "ipf") == 0)
359 		return (DDI_IDENTIFIED);
360 	return (DDI_NOT_IDENTIFIED);
361 }
362 #endif
363 
364 /*
365  * Initialize things for IPF for each stack instance
366  */
367 static void *
368 ipf_stack_create(const netid_t id)
369 {
370 	ipf_stack_t	*ifs;
371 
372 #ifdef IPFDEBUG
373 	cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id);
374 #endif
375 
376 	ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
377 	bzero(ifs, sizeof (*ifs));
378 
379 	ifs->ifs_hook4_physical_in	= B_FALSE;
380 	ifs->ifs_hook4_physical_out	= B_FALSE;
381 	ifs->ifs_hook4_nic_events	= B_FALSE;
382 	ifs->ifs_hook4_loopback_in	= B_FALSE;
383 	ifs->ifs_hook4_loopback_out	= B_FALSE;
384 	ifs->ifs_hook6_physical_in	= B_FALSE;
385 	ifs->ifs_hook6_physical_out	= B_FALSE;
386 	ifs->ifs_hook6_nic_events	= B_FALSE;
387 	ifs->ifs_hook6_loopback_in	= B_FALSE;
388 	ifs->ifs_hook6_loopback_out	= B_FALSE;
389 
390 	/*
391 	 * Initialize mutex's
392 	 */
393 	RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
394 	RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
395 
396 	ifs->ifs_netid = id;
397 	ifs->ifs_zone = net_getzoneidbynetid(id);
398 	ipf_kstat_init(ifs);
399 
400 #ifdef IPFDEBUG
401 	cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
402 #endif
403 
404 	/*
405 	 * Lock people out while we set things up.
406 	 */
407 	WRITE_ENTER(&ifs->ifs_ipf_global);
408 	ipftuneable_alloc(ifs);
409 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
410 
411 	/* Limit to global stack */
412 	if (ifs->ifs_zone == GLOBAL_ZONEID)
413 		cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
414 
415 	mutex_enter(&ipf_stack_lock);
416 	if (ipf_stacks != NULL)
417 		ipf_stacks->ifs_pnext = &ifs->ifs_next;
418 	ifs->ifs_next = ipf_stacks;
419 	ifs->ifs_pnext = &ipf_stacks;
420 	ipf_stacks = ifs;
421 	mutex_exit(&ipf_stack_lock);
422 
423 	return (ifs);
424 }
425 
426 
427 /*
428  * This function should only ever be used to find the pointer to the
429  * ipfilter stack structure for the zone that is currently being
430  * executed... so if you're running in the context of zone 1, you
431  * should not attempt to find the ipf_stack_t for zone 0 or 2 or
432  * anything else but 1.  In that way, the returned pointer is safe
433  * as it will only be nuked when the instance is destroyed as part
434  * of the final shutdown of a zone.
435  */
436 ipf_stack_t *ipf_find_stack(const zoneid_t zone)
437 {
438 	ipf_stack_t *ifs;
439 
440 	mutex_enter(&ipf_stack_lock);
441 	for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
442 		if (ifs->ifs_zone == zone)
443 			break;
444 	}
445 	mutex_exit(&ipf_stack_lock);
446 	return ifs;
447 }
448 
449 
450 static int ipf_detach_check_zone(ipf_stack_t *ifs)
451 {
452 	/*
453 	 * Make sure we're the only one's modifying things.  With
454 	 * this lock others should just fall out of the loop.
455 	 */
456 	READ_ENTER(&ifs->ifs_ipf_global);
457 	if (ifs->ifs_fr_running == 1) {
458 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
459 		return (-1);
460 	}
461 
462 	/*
463 	 * Make sure there is no active filter rule.
464 	 */
465 	if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] ||
466 	    ifs->ifs_ipfilter[1][ifs->ifs_fr_active] ||
467 	    ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] ||
468 	    ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) {
469 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
470 		return (-1);
471 	}
472 
473 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
474 
475 	return (0);
476 }
477 
478 
479 static int ipf_detach_check_all()
480 {
481 	ipf_stack_t *ifs;
482 
483 	mutex_enter(&ipf_stack_lock);
484 	for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
485 		if (ipf_detach_check_zone(ifs) != 0)
486 			break;
487 	mutex_exit(&ipf_stack_lock);
488 	return ((ifs == NULL) ? 0 : -1);
489 }
490 
491 
492 /*
493  * Destroy things for ipf for one stack.
494  */
495 /* ARGSUSED */
496 static void
497 ipf_stack_destroy(const netid_t id, void *arg)
498 {
499 	ipf_stack_t *ifs = (ipf_stack_t *)arg;
500 	timeout_id_t tid;
501 
502 #ifdef IPFDEBUG
503 	(void) printf("ipf_stack_destroy(%p)\n", (void *)ifs);
504 #endif
505 
506 	/*
507 	 * Make sure we're the only one's modifying things.  With
508 	 * this lock others should just fall out of the loop.
509 	 */
510 	WRITE_ENTER(&ifs->ifs_ipf_global);
511 	if (ifs->ifs_fr_running == -2) {
512 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
513 		return;
514 	}
515 	ifs->ifs_fr_running = -2;
516 	tid = ifs->ifs_fr_timer_id;
517 	ifs->ifs_fr_timer_id = NULL;
518 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
519 
520 	mutex_enter(&ipf_stack_lock);
521 	if (ifs->ifs_next != NULL)
522 		ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
523 	*ifs->ifs_pnext = ifs->ifs_next;
524 	mutex_exit(&ipf_stack_lock);
525 
526 	ipf_kstat_fini(ifs);
527 
528 	if (tid != NULL)
529 		(void) untimeout(tid);
530 
531 	WRITE_ENTER(&ifs->ifs_ipf_global);
532 	if (ipldetach(ifs) != 0) {
533 		printf("ipf_stack_destroy: ipldetach failed\n");
534 	}
535 
536 	ipftuneable_free(ifs);
537 
538 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
539 	RW_DESTROY(&ifs->ifs_ipf_mutex);
540 	RW_DESTROY(&ifs->ifs_ipf_global);
541 
542 	KFREE(ifs);
543 }
544 
545 
546 static int ipf_attach(dip, cmd)
547 dev_info_t *dip;
548 ddi_attach_cmd_t cmd;
549 {
550 	char *s;
551 	int i;
552 	int instance;
553 
554 #ifdef	IPFDEBUG
555 	cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
556 #endif
557 
558 	switch (cmd)
559 	{
560 	case DDI_ATTACH:
561 		instance = ddi_get_instance(dip);
562 		/* Only one instance of ipf (instance 0) can be attached. */
563 		if (instance > 0)
564 			return DDI_FAILURE;
565 
566 #ifdef	IPFDEBUG
567 		cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
568 #endif
569 
570 		(void) ipf_property_g_update(dip);
571 
572 		for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) {
573 			s = strrchr(s, '/');
574 			if (s == NULL)
575 				continue;
576 			s++;
577 			if (ddi_create_minor_node(dip, s, S_IFCHR, i,
578 						  DDI_PSEUDO, 0) ==
579 			    DDI_FAILURE) {
580 				ddi_remove_minor_node(dip, NULL);
581 				goto attach_failed;
582 			}
583 		}
584 
585 		ipf_dev_info = dip;
586 
587 		ipfncb = net_instance_alloc(NETINFO_VERSION);
588 		ipfncb->nin_name = "ipf";
589 		ipfncb->nin_create = ipf_stack_create;
590 		ipfncb->nin_destroy = ipf_stack_destroy;
591 		ipfncb->nin_shutdown = NULL;
592 		i = net_instance_register(ipfncb);
593 
594 #ifdef IPFDEBUG
595 		cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
596 #endif
597 
598 		return DDI_SUCCESS;
599 		/* NOTREACHED */
600 	default:
601 		break;
602 	}
603 
604 attach_failed:
605 	ddi_prop_remove_all(dip);
606 	return DDI_FAILURE;
607 }
608 
609 
610 static int ipf_detach(dip, cmd)
611 dev_info_t *dip;
612 ddi_detach_cmd_t cmd;
613 {
614 	int i;
615 
616 #ifdef	IPFDEBUG
617 	cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
618 #endif
619 	switch (cmd) {
620 	case DDI_DETACH:
621 		if (ipf_detach_check_all() != 0)
622 			return DDI_FAILURE;
623 
624 		/* Undo what we did in ipf_attach, freeing resources
625 		 * and removing things we installed.  The system
626 		 * framework guarantees we are not active with this devinfo
627 		 * node in any other entry points at this time.
628 		 */
629 		ddi_prop_remove_all(dip);
630 		i = ddi_get_instance(dip);
631 		ddi_remove_minor_node(dip, NULL);
632 		if (i > 0) {
633 			cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i);
634 			return DDI_FAILURE;
635 		}
636 
637 		(void) net_instance_unregister(ipfncb);
638 		net_instance_free(ipfncb);
639 
640 		return DDI_SUCCESS;
641 		/* NOTREACHED */
642 	default:
643 		break;
644 	}
645 	cmn_err(CE_NOTE, "IP Filter: failed to detach\n");
646 	return DDI_FAILURE;
647 }
648 
649 
650 /*ARGSUSED*/
651 static int ipf_getinfo(dip, infocmd, arg, result)
652 dev_info_t *dip;
653 ddi_info_cmd_t infocmd;
654 void *arg, **result;
655 {
656 	int error;
657 
658 	error = DDI_FAILURE;
659 #ifdef	IPFDEBUG
660 	cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
661 #endif
662 	switch (infocmd) {
663 	case DDI_INFO_DEVT2DEVINFO:
664 		*result = ipf_dev_info;
665 		error = DDI_SUCCESS;
666 		break;
667 	case DDI_INFO_DEVT2INSTANCE:
668 		*result = (void *)0;
669 		error = DDI_SUCCESS;
670 		break;
671 	default:
672 		break;
673 	}
674 	return (error);
675 }
676 
677 
678 /*
679  * Fetch configuration file values that have been entered into the ipf.conf
680  * driver file.
681  */
682 static int ipf_property_g_update(dip)
683 dev_info_t *dip;
684 {
685 #ifdef DDI_NO_AUTODETACH
686 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
687 				DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) {
688 		cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed");
689 		return DDI_FAILURE;
690 	}
691 #else
692 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
693 				"ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) {
694 		cmn_err(CE_WARN, "!updating ddi-no-autodetach failed");
695 		return DDI_FAILURE;
696 	}
697 #endif
698 
699 	return DDI_SUCCESS;
700 }
701 
702 int ipf_property_update(dip, ifs)
703 dev_info_t *dip;
704 ipf_stack_t *ifs;
705 {
706 	ipftuneable_t *ipft;
707 	int64_t *i64p;
708 	char *name;
709 	u_int one;
710 	int *i32p;
711 	int err;
712 
713 	for (ipft = ifs->ifs_ipf_tuneables; (name = ipft->ipft_name) != NULL; ipft++) {
714 		one = 1;
715 		switch (ipft->ipft_sz)
716 		{
717 		case 4 :
718 			i32p = NULL;
719 			err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
720 							0, name, &i32p, &one);
721 			if (err == DDI_PROP_NOT_FOUND)
722 				continue;
723 #ifdef	IPFDEBUG
724 			cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
725 				name, err);
726 #endif
727 			if (err != DDI_PROP_SUCCESS)
728 				return err;
729 			if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max)
730 				*ipft->ipft_pint = *i32p;
731 			else
732 				err = DDI_PROP_CANNOT_DECODE;
733 			ddi_prop_free(i32p);
734 			break;
735 
736 #if SOLARIS2 > 8
737 		case 8 :
738 			i64p = NULL;
739 			err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip,
740 							  0, name, &i64p, &one);
741 			if (err == DDI_PROP_NOT_FOUND)
742 				continue;
743 # ifdef	IPFDEBUG
744 			cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n",
745 				name, err);
746 # endif
747 			if (err != DDI_PROP_SUCCESS)
748 				return err;
749 			if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max)
750 				*ipft->ipft_pint = *i64p;
751 			else
752 				err = DDI_PROP_CANNOT_DECODE;
753 			ddi_prop_free(i64p);
754 			break;
755 #endif
756 		default :
757 			break;
758 		}
759 		if (err != DDI_SUCCESS)
760 			break;
761 	}
762 	return err;
763 }
764