xref: /illumos-gate/usr/src/uts/common/inet/ipf/solaris.c (revision 40cdc2e8)
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 
60 extern	int	iplwrite __P((dev_t, struct uio *, cred_t *));
61 
62 static	int	ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t,
63 		    void *, void **));
64 #if SOLARIS2 < 10
65 static	int	ipf_identify __P((dev_info_t *));
66 #endif
67 static	int	ipf_attach __P((dev_info_t *, ddi_attach_cmd_t));
68 static	int	ipf_detach __P((dev_info_t *, ddi_detach_cmd_t));
69 static	void	*ipf_stack_create __P((const netid_t));
70 static	void	ipf_stack_destroy __P((const netid_t, void *));
71 static	int	ipf_property_g_update __P((dev_info_t *));
72 static	char	*ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
73 				    IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
74 				    IPLOOKUP_NAME, NULL };
75 
76 
77 static 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 
100 static 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 
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
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 
327 int
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 
340 int
341 _info(modinfop)
342 struct 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
355 static int ipf_identify(dip)
356 dev_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  */
370 static void *
371 ipf_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  */
439 ipf_stack_t *
440 ipf_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 
454 static 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 
483 static 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 */
500 static void
501 ipf_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 
550 static int ipf_attach(dip, cmd)
551 dev_info_t *dip;
552 ddi_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 
608 attach_failed:
609 	ddi_prop_remove_all(dip);
610 	return (DDI_FAILURE);
611 }
612 
613 
614 static int ipf_detach(dip, cmd)
615 dev_info_t *dip;
616 ddi_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*/
656 static int ipf_getinfo(dip, infocmd, arg, result)
657 dev_info_t *dip;
658 ddi_info_cmd_t infocmd;
659 void *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  */
687 static int ipf_property_g_update(dip)
688 dev_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 
707 int
708 ipf_property_update(dip, ifs)
709 dev_info_t *dip;
710 ipf_stack_t *ifs;
711 {
712 	ipftuneable_t *ipft;
713 	char *name;
714 	uint_t one;
715 	int *i32p;
716 	int err, rv = 0;
717 
718 	for (ipft = ifs->ifs_ipf_tuneables;
719 		(name = ipft->ipft_name) != NULL; ipft++) {
720 		one = 1;
721 		i32p = NULL;
722 		err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
723 						0, name, &i32p, &one);
724 		if (err == DDI_PROP_NOT_FOUND)
725 			continue;
726 #ifdef	IPFDEBUG
727 		cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n",
728 			name, err);
729 #endif
730 		if (err != DDI_PROP_SUCCESS) {
731 			rv = err;
732 			continue;
733 		}
734 
735 		if (*i32p >= ipft->ipft_min &&
736 		    *i32p <= ipft->ipft_max) {
737 			if (ipft->ipft_sz == sizeof (uint32_t)) {
738 				*ipft->ipft_pint = *i32p;
739 			} else if (ipft->ipft_sz == sizeof (uint64_t)) {
740 				*ipft->ipft_plong = *i32p;
741 			}
742 		}
743 
744 		ddi_prop_free(i32p);
745 	}
746 
747 	return (rv);
748 }
749