17c478bd9Sstevel@tonic-gate /*
2ab25eeb5Syz  * Copyright (C) 1993-2001, 2003 by Darren Reed.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
6d0dd088cSAlexandr Nedvedicky  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
794bdecd9SRob Gulewich  *
8ec71f88eSPatrick Mooney  * Copyright 2018 Joyent, Inc.
97c478bd9Sstevel@tonic-gate  */
117c478bd9Sstevel@tonic-gate #if !defined(lint)
12c793af95Ssangeeta static const char sccsid[] = "@(#)ip_fil_solaris.c	1.7 07/22/06 (C) 1993-2000 Darren Reed";
13ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2005/07/13 21:40:46 darrenr Exp $";
147c478bd9Sstevel@tonic-gate #endif
167c478bd9Sstevel@tonic-gate #include <sys/types.h>
177c478bd9Sstevel@tonic-gate #include <sys/errno.h>
187c478bd9Sstevel@tonic-gate #include <sys/param.h>
197c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
207c478bd9Sstevel@tonic-gate #include <sys/open.h>
217c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
227c478bd9Sstevel@tonic-gate #include <sys/filio.h>
237c478bd9Sstevel@tonic-gate #include <sys/systm.h>
24ab25eeb5Syz #include <sys/strsubr.h>
25*b22a70abSPatrick Mooney #include <sys/strsun.h>
267c478bd9Sstevel@tonic-gate #include <sys/cred.h>
277c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
287c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
297c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
31ec71f88eSPatrick Mooney #include <sys/mac_provider.h>
327c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
337c478bd9Sstevel@tonic-gate #include <sys/protosw.h>
347c478bd9Sstevel@tonic-gate #include <sys/socket.h>
357c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
37f4b3ec61Sdh #include <sys/zone.h>
387c478bd9Sstevel@tonic-gate #include <net/if.h>
397c478bd9Sstevel@tonic-gate #include <net/af.h>
407c478bd9Sstevel@tonic-gate #include <net/route.h>
417c478bd9Sstevel@tonic-gate #include <netinet/in.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
437c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
447c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h>
457c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
467c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
477c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h>
487c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
49ab25eeb5Syz #include "netinet/ip_compat.h"
507c478bd9Sstevel@tonic-gate #ifdef	USE_INET6
517c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h>
527c478bd9Sstevel@tonic-gate #endif
53ab25eeb5Syz #include "netinet/ip_fil.h"
54ab25eeb5Syz #include "netinet/ip_nat.h"
55ab25eeb5Syz #include "netinet/ip_frag.h"
56ab25eeb5Syz #include "netinet/ip_state.h"
57ab25eeb5Syz #include "netinet/ip_auth.h"
58ab25eeb5Syz #include "netinet/ip_proxy.h"
59f4b3ec61Sdh #include "netinet/ipf_stack.h"
607c478bd9Sstevel@tonic-gate #ifdef	IPFILTER_LOOKUP
61ab25eeb5Syz # include "netinet/ip_lookup.h"
627c478bd9Sstevel@tonic-gate #endif
637c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h>
657c478bd9Sstevel@tonic-gate #include <sys/md5.h>
66381a2a9aSdr #include <sys/neti.h>
68f4b3ec61Sdh static	int	frzerostats __P((caddr_t, ipf_stack_t *));
69f4b3ec61Sdh static	int	fr_setipfloopback __P((int, ipf_stack_t *));
707ddc9b1aSDarren Reed static	int	fr_enableipf __P((ipf_stack_t *, int));
71ab25eeb5Syz static	int	fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp));
727ddc9b1aSDarren Reed static	int	ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *));
737ddc9b1aSDarren Reed static	int	ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *));
747ddc9b1aSDarren Reed static	int	ipf_hook __P((hook_data_t, int, int, void *));
757ddc9b1aSDarren Reed static	int	ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *));
767ddc9b1aSDarren Reed static	int	ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *));
77cbded9aeSdr static	int	ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t,
787ddc9b1aSDarren Reed     void *));
797ddc9b1aSDarren Reed static	int	ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *));
807ddc9b1aSDarren Reed static	int	ipf_hook4 __P((hook_data_t, int, int, void *));
817ddc9b1aSDarren Reed static	int	ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *));
827ddc9b1aSDarren Reed static	int	ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *));
83cbded9aeSdr static	int	ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t,
847ddc9b1aSDarren Reed     void *));
85cbded9aeSdr static	int	ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t,
867ddc9b1aSDarren Reed     void *));
877ddc9b1aSDarren Reed static	int     ipf_hook6 __P((hook_data_t, int, int, void *));
88*b22a70abSPatrick Mooney 
89*b22a70abSPatrick Mooney static	int	ipf_hookviona_in __P((hook_event_token_t, hook_data_t, void *));
90*b22a70abSPatrick Mooney static	int	ipf_hookviona_out __P((hook_event_token_t, hook_data_t,
91*b22a70abSPatrick Mooney     void *));
92*b22a70abSPatrick Mooney 
93f4b3ec61Sdh extern	int	ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
94f4b3ec61Sdh extern	int	ipf_frruleiter __P((void *, int, void *, ipf_stack_t *));
96*b22a70abSPatrick Mooney static int	ipf_hook_protocol_notify __P((hook_notify_cmd_t, void *,
97*b22a70abSPatrick Mooney     const char *, const char *, const char *));
98*b22a70abSPatrick Mooney static int	ipf_hook_instance_notify __P((hook_notify_cmd_t, void *,
99*b22a70abSPatrick Mooney     const char *, const char *, const char *));
100*b22a70abSPatrick Mooney 
1017c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10
1027c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 7
103ab25eeb5Syz u_int		*ip_ttl_ptr = NULL;
104ab25eeb5Syz u_int		*ip_mtudisc = NULL;
1057c478bd9Sstevel@tonic-gate # if SOLARIS2 >= 8
106ab25eeb5Syz int		*ip_forwarding = NULL;
107ab25eeb5Syz u_int		*ip6_forwarding = NULL;
1087c478bd9Sstevel@tonic-gate # else
109ab25eeb5Syz u_int		*ip_forwarding = NULL;
1107c478bd9Sstevel@tonic-gate # endif
1117c478bd9Sstevel@tonic-gate #else
112ab25eeb5Syz u_long		*ip_ttl_ptr = NULL;
113ab25eeb5Syz u_long		*ip_mtudisc = NULL;
114ab25eeb5Syz u_long		*ip_forwarding = NULL;
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate #endif
11894bdecd9SRob Gulewich vmem_t	*ipf_minor;	/* minor number arena */
11994bdecd9SRob Gulewich void 	*ipf_state;	/* DDI state */
12094bdecd9SRob Gulewich 
12194bdecd9SRob Gulewich /*
12294bdecd9SRob Gulewich  * GZ-controlled and per-zone stacks:
12394bdecd9SRob Gulewich  *
12494bdecd9SRob Gulewich  * For each non-global zone, we create two ipf stacks: the per-zone stack and
12594bdecd9SRob Gulewich  * the GZ-controlled stack.  The per-zone stack can be controlled and observed
12694bdecd9SRob Gulewich  * from inside the zone or from the global zone.  The GZ-controlled stack can
12794bdecd9SRob Gulewich  * only be controlled and observed from the global zone (though the rules
12894bdecd9SRob Gulewich  * still only affect that non-global zone).
12994bdecd9SRob Gulewich  *
13094bdecd9SRob Gulewich  * The two hooks are always arranged so that the GZ-controlled stack is always
13194bdecd9SRob Gulewich  * "outermost" with respect to the zone.  The traffic flow then looks like
13294bdecd9SRob Gulewich  * this:
13394bdecd9SRob Gulewich  *
13494bdecd9SRob Gulewich  * Inbound:
13594bdecd9SRob Gulewich  *
13694bdecd9SRob Gulewich  *     nic ---> [ GZ-controlled rules ] ---> [ per-zone rules ] ---> zone
13794bdecd9SRob Gulewich  *
13894bdecd9SRob Gulewich  * Outbound:
13994bdecd9SRob Gulewich  *
14094bdecd9SRob Gulewich  *     nic <--- [ GZ-controlled rules ] <--- [ per-zone rules ] <--- zone
14194bdecd9SRob Gulewich  */
14294bdecd9SRob Gulewich 
14394bdecd9SRob Gulewich /* IPv4 hook names */
14494bdecd9SRob Gulewich char *hook4_nicevents = 	"ipfilter_hook4_nicevents";
14594bdecd9SRob Gulewich char *hook4_nicevents_gz = 	"ipfilter_hook4_nicevents_gz";
14694bdecd9SRob Gulewich char *hook4_in = 		"ipfilter_hook4_in";
14794bdecd9SRob Gulewich char *hook4_in_gz = 		"ipfilter_hook4_in_gz";
14894bdecd9SRob Gulewich char *hook4_out = 		"ipfilter_hook4_out";
14994bdecd9SRob Gulewich char *hook4_out_gz = 		"ipfilter_hook4_out_gz";
15094bdecd9SRob Gulewich char *hook4_loop_in = 		"ipfilter_hook4_loop_in";
15194bdecd9SRob Gulewich char *hook4_loop_in_gz = 	"ipfilter_hook4_loop_in_gz";
15294bdecd9SRob Gulewich char *hook4_loop_out = 		"ipfilter_hook4_loop_out";
15394bdecd9SRob Gulewich char *hook4_loop_out_gz = 	"ipfilter_hook4_loop_out_gz";
15494bdecd9SRob Gulewich 
15594bdecd9SRob Gulewich /* IPv6 hook names */
15694bdecd9SRob Gulewich char *hook6_nicevents = 	"ipfilter_hook6_nicevents";
15794bdecd9SRob Gulewich char *hook6_nicevents_gz = 	"ipfilter_hook6_nicevents_gz";
15894bdecd9SRob Gulewich char *hook6_in = 		"ipfilter_hook6_in";
15994bdecd9SRob Gulewich char *hook6_in_gz = 		"ipfilter_hook6_in_gz";
16094bdecd9SRob Gulewich char *hook6_out = 		"ipfilter_hook6_out";
16194bdecd9SRob Gulewich char *hook6_out_gz = 		"ipfilter_hook6_out_gz";
16294bdecd9SRob Gulewich char *hook6_loop_in = 		"ipfilter_hook6_loop_in";
16394bdecd9SRob Gulewich char *hook6_loop_in_gz = 	"ipfilter_hook6_loop_in_gz";
16494bdecd9SRob Gulewich char *hook6_loop_out = 		"ipfilter_hook6_loop_out";
16594bdecd9SRob Gulewich char *hook6_loop_out_gz = 	"ipfilter_hook6_loop_out_gz";
167*b22a70abSPatrick Mooney /* viona hook names */
168*b22a70abSPatrick Mooney char *hook_viona_in =		"ipfilter_hookviona_in";
169*b22a70abSPatrick Mooney char *hook_viona_in_gz =	"ipfilter_hookviona_in_gz";
170*b22a70abSPatrick Mooney char *hook_viona_out =		"ipfilter_hookviona_out";
171*b22a70abSPatrick Mooney char *hook_viona_out_gz =	"ipfilter_hookviona_out_gz";
172*b22a70abSPatrick Mooney 
1737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
1747c478bd9Sstevel@tonic-gate /* Function:    ipldetach                                                   */
1757c478bd9Sstevel@tonic-gate /* Returns:     int - 0 == success, else error.                             */
1767c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
1777c478bd9Sstevel@tonic-gate /*                                                                          */
1787c478bd9Sstevel@tonic-gate /* This function is responsible for undoing anything that might have been   */
1797c478bd9Sstevel@tonic-gate /* done in a call to iplattach().  It must be able to clean up from a call  */
1807c478bd9Sstevel@tonic-gate /* to iplattach() that did not succeed.  Why might that happen?  Someone    */
1817c478bd9Sstevel@tonic-gate /* configures a table to be so large that we cannot allocate enough memory  */
1827c478bd9Sstevel@tonic-gate /* for it.                                                                  */
1837c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
ipldetach(ifs)184f4b3ec61Sdh int ipldetach(ifs)
185f4b3ec61Sdh ipf_stack_t *ifs;
1867c478bd9Sstevel@tonic-gate {
18894bdecd9SRob Gulewich 	ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk));
1907c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10
192f4b3ec61Sdh 	if (ifs->ifs_fr_control_forwarding & 2) {
193ab25eeb5Syz 		if (ip_forwarding != NULL)
194ab25eeb5Syz 			*ip_forwarding = 0;
1957c478bd9Sstevel@tonic-gate #if SOLARIS2 >= 8
196ab25eeb5Syz 		if (ip6_forwarding != NULL)
197ab25eeb5Syz 			*ip6_forwarding = 0;
1987c478bd9Sstevel@tonic-gate #endif
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate #endif
202381a2a9aSdr 	/*
2037ddc9b1aSDarren Reed 	 * This lock needs to be dropped around the net_hook_unregister calls
204381a2a9aSdr 	 * because we can deadlock here with:
205381a2a9aSdr 	 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
206381a2a9aSdr 	 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running)
207381a2a9aSdr 	 */
208f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
2107ddc9b1aSDarren Reed #define	UNDO_HOOK(_f, _b, _e, _h)					\
2117ddc9b1aSDarren Reed 	do {								\
2127ddc9b1aSDarren Reed 		if (ifs->_f != NULL) {					\
2137ddc9b1aSDarren Reed 			if (ifs->_b) {					\
214c6798761SJerry Jelinek 				int tmp = net_hook_unregister(ifs->_f,	\
215c6798761SJerry Jelinek 					   _e, ifs->_h);		\
216c6798761SJerry Jelinek 				ifs->_b = (tmp != 0 && tmp != ENXIO);	\
217c6798761SJerry Jelinek 				if (!ifs->_b && ifs->_h != NULL) {	\
2187ddc9b1aSDarren Reed 					hook_free(ifs->_h);		\
2197ddc9b1aSDarren Reed 					ifs->_h = NULL;			\
2207ddc9b1aSDarren Reed 				}					\
2217ddc9b1aSDarren Reed 			} else if (ifs->_h != NULL) {			\
2227ddc9b1aSDarren Reed 				hook_free(ifs->_h);			\
2237ddc9b1aSDarren Reed 				ifs->_h = NULL;				\
2247ddc9b1aSDarren Reed 			}						\
2257ddc9b1aSDarren Reed 		}							\
2267ddc9b1aSDarren Reed 		_NOTE(CONSTCOND)					\
2277ddc9b1aSDarren Reed 	} while (0)
2287ddc9b1aSDarren Reed 
229381a2a9aSdr 	/*
230381a2a9aSdr 	 * Remove IPv6 Hooks
231381a2a9aSdr 	 */
232f4b3ec61Sdh 	if (ifs->ifs_ipf_ipv6 != NULL) {
2337ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in,
2347ddc9b1aSDarren Reed 			  NH_PHYSICAL_IN, ifs_ipfhook6_in);
2357ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out,
2367ddc9b1aSDarren Reed 			  NH_PHYSICAL_OUT, ifs_ipfhook6_out);
2377ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events,
2387ddc9b1aSDarren Reed 			  NH_NIC_EVENTS, ifs_ipfhook6_nicevents);
2397ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in,
2407ddc9b1aSDarren Reed 			  NH_LOOPBACK_IN, ifs_ipfhook6_loop_in);
2417ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out,
2427ddc9b1aSDarren Reed 			  NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out);
2437ddc9b1aSDarren Reed 
2447ddc9b1aSDarren Reed 		if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0)
245381a2a9aSdr 			goto detach_failed;
246f4b3ec61Sdh 		ifs->ifs_ipf_ipv6 = NULL;
247381a2a9aSdr         }
249381a2a9aSdr 	/*
250381a2a9aSdr 	 * Remove IPv4 Hooks
251381a2a9aSdr 	 */
252f4b3ec61Sdh 	if (ifs->ifs_ipf_ipv4 != NULL) {
2537ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in,
2547ddc9b1aSDarren Reed 			  NH_PHYSICAL_IN, ifs_ipfhook4_in);
2557ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out,
2567ddc9b1aSDarren Reed 			  NH_PHYSICAL_OUT, ifs_ipfhook4_out);
2577ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events,
2587ddc9b1aSDarren Reed 			  NH_NIC_EVENTS, ifs_ipfhook4_nicevents);
2597ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in,
2607ddc9b1aSDarren Reed 			  NH_LOOPBACK_IN, ifs_ipfhook4_loop_in);
2617ddc9b1aSDarren Reed 		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out,
2627ddc9b1aSDarren Reed 			  NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out);
2637ddc9b1aSDarren Reed 
2647ddc9b1aSDarren Reed 		if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0)
265381a2a9aSdr 			goto detach_failed;
266f4b3ec61Sdh 		ifs->ifs_ipf_ipv4 = NULL;
267381a2a9aSdr 	}
269*b22a70abSPatrick Mooney 	/*
270*b22a70abSPatrick Mooney 	 * Remove notification of viona hooks
271*b22a70abSPatrick Mooney 	 */
272*b22a70abSPatrick Mooney 	net_instance_notify_unregister(ifs->ifs_netid,
273*b22a70abSPatrick Mooney 	    ipf_hook_instance_notify);
274*b22a70abSPatrick Mooney 
2757ddc9b1aSDarren Reed #undef UNDO_HOOK
2767ddc9b1aSDarren Reed 
277*b22a70abSPatrick Mooney 	/*
278*b22a70abSPatrick Mooney 	 * Normally, viona will unregister itself before ipldetach() is called,
279*b22a70abSPatrick Mooney 	 * so these will be no-ops, but out of caution, we try to make sure
280*b22a70abSPatrick Mooney 	 * we've removed any of our references.
281*b22a70abSPatrick Mooney 	 */
282*b22a70abSPatrick Mooney 	(void) ipf_hook_protocol_notify(HN_UNREGISTER, ifs, Hn_VIONA, NULL,
283*b22a70abSPatrick Mooney 	    NH_PHYSICAL_IN);
284*b22a70abSPatrick Mooney 	(void) ipf_hook_protocol_notify(HN_UNREGISTER, ifs, Hn_VIONA, NULL,
285*b22a70abSPatrick Mooney 	    NH_PHYSICAL_OUT);
286*b22a70abSPatrick Mooney 
287*b22a70abSPatrick Mooney 	{
288*b22a70abSPatrick Mooney 		char netidstr[12]; /* Large enough for INT_MAX + NUL */
289*b22a70abSPatrick Mooney 		(void) snprintf(netidstr, sizeof (netidstr), "%d",
290*b22a70abSPatrick Mooney 		    ifs->ifs_netid);
291*b22a70abSPatrick Mooney 
292*b22a70abSPatrick Mooney 		/*
293*b22a70abSPatrick Mooney 		 * The notify callbacks expect the netid value passed as a
294*b22a70abSPatrick Mooney 		 * string in the third argument.  To prevent confusion if
295*b22a70abSPatrick Mooney 		 * traced, we pass the same value the nethook framework would
296*b22a70abSPatrick Mooney 		 * pass, even though the callback does not currently use the
297*b22a70abSPatrick Mooney 		 * value.
298*b22a70abSPatrick Mooney 		 */
299*b22a70abSPatrick Mooney 		(void) ipf_hook_instance_notify(HN_UNREGISTER, ifs, netidstr,
300*b22a70abSPatrick Mooney 		    NULL, Hn_VIONA);
301*b22a70abSPatrick Mooney 	}
302*b22a70abSPatrick Mooney 
3037c478bd9Sstevel@tonic-gate #ifdef	IPFDEBUG
3047c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "ipldetach()\n");
3057c478bd9Sstevel@tonic-gate #endif
307f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_global);
308f4b3ec61Sdh 	fr_deinitialise(ifs);
310f4b3ec61Sdh 	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs);
311f4b3ec61Sdh 	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs);
313f4b3ec61Sdh 	if (ifs->ifs_ipf_locks_done == 1) {
314f4b3ec61Sdh 		MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock);
315f4b3ec61Sdh 		MUTEX_DESTROY(&ifs->ifs_ipf_rw);
316f4b3ec61Sdh 		RW_DESTROY(&ifs->ifs_ipf_tokens);
317f4b3ec61Sdh 		RW_DESTROY(&ifs->ifs_ipf_ipidfrag);
318f4b3ec61Sdh 		ifs->ifs_ipf_locks_done = 0;
3197c478bd9Sstevel@tonic-gate 	}
3217ddc9b1aSDarren Reed 	if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out ||
3227ddc9b1aSDarren Reed 	    ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in ||
3237ddc9b1aSDarren Reed 	    ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
3247ddc9b1aSDarren Reed 	    ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out ||
3257ddc9b1aSDarren Reed 	    ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out)
326381a2a9aSdr 		return -1;
3287c478bd9Sstevel@tonic-gate 	return 0;
330381a2a9aSdr detach_failed:
331f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_global);
332381a2a9aSdr 	return -1;
3337c478bd9Sstevel@tonic-gate }
iplattach(ifs)3357ddc9b1aSDarren Reed int iplattach(ifs)
336f4b3ec61Sdh ipf_stack_t *ifs;
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate #if SOLARIS2 < 10
3397c478bd9Sstevel@tonic-gate 	int i;
3407c478bd9Sstevel@tonic-gate #endif
3417ddc9b1aSDarren Reed 	netid_t id = ifs->ifs_netid;
3437c478bd9Sstevel@tonic-gate #ifdef	IPFDEBUG
3447c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "iplattach()\n");
3457c478bd9Sstevel@tonic-gate #endif
34794bdecd9SRob Gulewich 	ASSERT(RW_WRITE_HELD(&ifs->ifs_ipf_global.ipf_lk));
348f4b3ec61Sdh 	ifs->ifs_fr_flags = IPF_LOGGING;
349f4b3ec61Sdh #ifdef _KERNEL
350f4b3ec61Sdh 	ifs->ifs_fr_update_ipid = 0;
351f4b3ec61Sdh #else
352f4b3ec61Sdh 	ifs->ifs_fr_update_ipid = 1;
353f4b3ec61Sdh #endif
354f4b3ec61Sdh 	ifs->ifs_fr_minttl = 4;
355f4b3ec61Sdh 	ifs->ifs_fr_icmpminfragmtu = 68;
356f4b3ec61Sdh #if defined(IPFILTER_DEFAULT_BLOCK)
357f4b3ec61Sdh 	ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
358f4b3ec61Sdh #else
359f4b3ec61Sdh 	ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
360f4b3ec61Sdh #endif
36214d3298eSAlexandr Nedvedicky 	bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache));
363f4b3ec61Sdh 	MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex");
364f4b3ec61Sdh 	MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex");
365f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
366f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock");
367f4b3ec61Sdh 	ifs->ifs_ipf_locks_done = 1;
369f4b3ec61Sdh 	if (fr_initialise(ifs) < 0)
3707c478bd9Sstevel@tonic-gate 		return -1;
37294bdecd9SRob Gulewich 	/*
37394bdecd9SRob Gulewich 	 * For incoming packets, we want the GZ-controlled hooks to run before
37494bdecd9SRob Gulewich 	 * the per-zone hooks, regardless of what order they're are installed.
37594bdecd9SRob Gulewich 	 * See the "GZ-controlled and per-zone stacks" comment block at the top
37694bdecd9SRob Gulewich 	 * of this file.
37794bdecd9SRob Gulewich 	 */
37894bdecd9SRob Gulewich #define HOOK_INIT_GZ_BEFORE(x, fn, n, gzn, a)				\
37994bdecd9SRob Gulewich 	HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs);	\
38094bdecd9SRob Gulewich 	(x)->h_hint = ifs->ifs_gz_controlled ? HH_BEFORE : HH_AFTER;	\
38194bdecd9SRob Gulewich 	(x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn);
38294bdecd9SRob Gulewich 
38394bdecd9SRob Gulewich 	HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4,
38494bdecd9SRob Gulewich 		  hook4_nicevents, hook4_nicevents_gz, ifs);
38594bdecd9SRob Gulewich 	HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_in, ipf_hook4_in,
38694bdecd9SRob Gulewich 		  hook4_in, hook4_in_gz, ifs);
38794bdecd9SRob Gulewich 	HOOK_INIT_GZ_BEFORE(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in,
38894bdecd9SRob Gulewich 		  hook4_loop_in, hook4_loop_in_gz, ifs);
38994bdecd9SRob Gulewich 
39094bdecd9SRob Gulewich 	/*
39194bdecd9SRob Gulewich 	 * For outgoing packets, we want the GZ-controlled hooks to run after
39294bdecd9SRob Gulewich 	 * the per-zone hooks, regardless of what order they're are installed.
39394bdecd9SRob Gulewich 	 * See the "GZ-controlled and per-zone stacks" comment block at the top
39494bdecd9SRob Gulewich 	 * of this file.
39594bdecd9SRob Gulewich 	 */
39694bdecd9SRob Gulewich #define HOOK_INIT_GZ_AFTER(x, fn, n, gzn, a)				\
39794bdecd9SRob Gulewich 	HOOK_INIT(x, fn, ifs->ifs_gz_controlled ? gzn : n, ifs);	\
39894bdecd9SRob Gulewich 	(x)->h_hint = ifs->ifs_gz_controlled ? HH_AFTER : HH_BEFORE;	\
39994bdecd9SRob Gulewich 	(x)->h_hintvalue = (uintptr_t) (ifs->ifs_gz_controlled ? n : gzn);
40094bdecd9SRob Gulewich 
40194bdecd9SRob Gulewich 	HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_out, ipf_hook4_out,
40294bdecd9SRob Gulewich 		  hook4_out, hook4_out_gz, ifs);
40394bdecd9SRob Gulewich 	HOOK_INIT_GZ_AFTER(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out,
40494bdecd9SRob Gulewich 		  hook4_loop_out, hook4_loop_out_gz, ifs);
406381a2a9aSdr 	/*
4077ddc9b1aSDarren Reed 	 * If we hold this lock over all of the net_hook_register calls, we
408381a2a9aSdr 	 * can cause a deadlock to occur with the following lock ordering:
409381a2a9aSdr 	 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
410381a2a9aSdr 	 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path)
411381a2a9aSdr 	 */
412f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
414381a2a9aSdr 	/*
415381a2a9aSdr 	 * Add IPv4 hooks
416381a2a9aSdr 	 */
4177ddc9b1aSDarren Reed 	ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET);
418f4b3ec61Sdh 	if (ifs->ifs_ipf_ipv4 == NULL)
419381a2a9aSdr 		goto hookup_failed;
4217ddc9b1aSDarren Reed 	ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4,
4227ddc9b1aSDarren Reed 	    NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0);
423f4b3ec61Sdh 	if (!ifs->ifs_hook4_nic_events)
424381a2a9aSdr 		goto hookup_failed;
4267ddc9b1aSDarren Reed 	ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4,