ip_fil_solaris.c revision 7704:c2487b19c177
1139749Simp/*
2119853Scg * Copyright (C) 1993-2001, 2003 by Darren Reed.
3166426Sjoel *
458756Scg * See the IPFILTER.LICENCE file for details on licencing.
558756Scg *
658756Scg * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
758756Scg * Use is subject to license terms.
858756Scg */
958756Scg
1058756Scg#if !defined(lint)
1158756Scgstatic const char sccsid[] = "@(#)ip_fil_solaris.c	1.7 07/22/06 (C) 1993-2000 Darren Reed";
1258756Scgstatic const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $";
1358756Scg#endif
1458756Scg
1558756Scg#include <sys/types.h>
1658756Scg#include <sys/errno.h>
1758756Scg#include <sys/param.h>
1858756Scg#include <sys/cpuvar.h>
1958756Scg#include <sys/open.h>
2058756Scg#include <sys/ioctl.h>
2158756Scg#include <sys/filio.h>
2258756Scg#include <sys/systm.h>
2358756Scg#include <sys/strsubr.h>
2458756Scg#include <sys/cred.h>
2558756Scg#include <sys/cred_impl.h>
2658756Scg#include <sys/ddi.h>
2758756Scg#include <sys/sunddi.h>
2858756Scg#include <sys/ksynch.h>
2958756Scg#include <sys/kmem.h>
3058756Scg#include <sys/mkdev.h>
3158756Scg#include <sys/protosw.h>
3258756Scg#include <sys/socket.h>
3358756Scg#include <sys/dditypes.h>
3458756Scg#include <sys/cmn_err.h>
3558756Scg#include <sys/zone.h>
3658756Scg#include <net/if.h>
37110499Snyan#include <net/af.h>
38110499Snyan#include <net/route.h>
3970134Scg#include <netinet/in.h>
4070134Scg#include <netinet/in_systm.h>
4182180Scg#include <netinet/ip.h>
4282180Scg#include <netinet/ip_var.h>
4359323Scg#include <netinet/tcp.h>
4458756Scg#include <netinet/udp.h>
4558756Scg#include <netinet/tcpip.h>
4658756Scg#include <netinet/ip_icmp.h>
4758756Scg#include "netinet/ip_compat.h"
4858756Scg#ifdef	USE_INET6
4958756Scg# include <netinet/icmp6.h>
5058756Scg#endif
5158756Scg#include "netinet/ip_fil.h"
5264881Scg#include "netinet/ip_nat.h"
5364881Scg#include "netinet/ip_frag.h"
5464881Scg#include "netinet/ip_state.h"
5564881Scg#include "netinet/ip_auth.h"
5664881Scg#include "netinet/ip_proxy.h"
5764881Scg#include "netinet/ipf_stack.h"
5864881Scg#ifdef	IPFILTER_LOOKUP
5964881Scg# include "netinet/ip_lookup.h"
6064881Scg#endif
6164881Scg#include <inet/ip_ire.h>
6258756Scg
6358756Scg#include <sys/md5.h>
64154438Sariff#include <sys/neti.h>
6564881Scg
6664881Scgstatic	int	frzerostats __P((caddr_t, ipf_stack_t *));
6764881Scgstatic	int	fr_setipfloopback __P((int, ipf_stack_t *));
6864881Scgstatic	int	fr_enableipf __P((ipf_stack_t *, int));
6964881Scgstatic	int	fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp));
7064881Scgstatic	int	ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *));
7164881Scgstatic	int	ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *));
7264881Scgstatic	int	ipf_hook __P((hook_data_t, int, int, void *));
7364881Scgstatic	int	ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *));
7464881Scgstatic	int	ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *));
7564881Scgstatic	int	ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t,
7658756Scg    void *));
7758756Scgstatic	int	ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *));
78154438Sariffstatic	int	ipf_hook4 __P((hook_data_t, int, int, void *));
7964881Scgstatic	int	ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *));
8058756Scgstatic	int	ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *));
8158756Scgstatic	int	ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t,
8258756Scg    void *));
8358756Scgstatic	int	ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t,
8474763Scg    void *));
8574763Scgstatic	int     ipf_hook6 __P((hook_data_t, int, int, void *));
8670134Scgextern	int	ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
8770291Scgextern	int	ipf_frruleiter __P((void *, int, void *, ipf_stack_t *));
8858756Scg
8958756Scg#if SOLARIS2 < 10
9058756Scg#if SOLARIS2 >= 7
9174763Scgu_int		*ip_ttl_ptr = NULL;
9258756Scgu_int		*ip_mtudisc = NULL;
9358756Scg# if SOLARIS2 >= 8
9458756Scgint		*ip_forwarding = NULL;
9558756Scgu_int		*ip6_forwarding = NULL;
9665644Scg# else
9758756Scgu_int		*ip_forwarding = NULL;
9858756Scg# endif
9984111Scg#else
100170032Sariffu_long		*ip_ttl_ptr = NULL;
101170032Sariffu_long		*ip_mtudisc = NULL;
10258756Scgu_long		*ip_forwarding = NULL;
10358756Scg#endif
10458756Scg#endif
10558756Scg
10684111Scg
10758756Scg/* ------------------------------------------------------------------------ */
10858756Scg/* Function:    ipldetach                                                   */
10958756Scg/* Returns:     int - 0 == success, else error.                             */
11058756Scg/* Parameters:  Nil                                                         */
11158756Scg/*                                                                          */
11258756Scg/* This function is responsible for undoing anything that might have been   */
11358756Scg/* done in a call to iplattach().  It must be able to clean up from a call  */
11458756Scg/* to iplattach() that did not succeed.  Why might that happen?  Someone    */
11558756Scg/* configures a table to be so large that we cannot allocate enough memory  */
11658756Scg/* for it.                                                                  */
11758756Scg/* ------------------------------------------------------------------------ */
11858756Scgint ipldetach(ifs)
11958756Scgipf_stack_t *ifs;
12058756Scg{
12158756Scg
12258756Scg	ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
12358756Scg
12484111Scg#if SOLARIS2 < 10
12558756Scg
12658756Scg	if (ifs->ifs_fr_control_forwarding & 2) {
12758756Scg		if (ip_forwarding != NULL)
12858756Scg			*ip_forwarding = 0;
12958756Scg#if SOLARIS2 >= 8
13058756Scg		if (ip6_forwarding != NULL)
13158756Scg			*ip6_forwarding = 0;
13258756Scg#endif
13358756Scg	}
13458756Scg#endif
13558756Scg
13658756Scg	/*
13758756Scg	 * This lock needs to be dropped around the net_hook_unregister calls
13874763Scg	 * because we can deadlock here with:
13974763Scg	 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
14074763Scg	 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running)
14174763Scg	 */
14274763Scg	RWLOCK_EXIT(&ifs->ifs_ipf_global);
14374763Scg
14474763Scg#define	UNDO_HOOK(_f, _b, _e, _h)					\
14574763Scg	do {								\
14674763Scg		if (ifs->_f != NULL) {					\
14774763Scg			if (ifs->_b) {					\
14874763Scg				ifs->_b = (net_hook_unregister(ifs->_f,	\
14974763Scg					   _e, ifs->_h) != 0);		\
15058756Scg				if (!ifs->_b) {				\
15158756Scg					hook_free(ifs->_h);		\
15258756Scg					ifs->_h = NULL;			\
15358756Scg				}					\
15458756Scg			} else if (ifs->_h != NULL) {			\
15558756Scg				hook_free(ifs->_h);			\
15658756Scg				ifs->_h = NULL;				\
15758756Scg			}						\
15858756Scg		}							\
15958756Scg		_NOTE(CONSTCOND)					\
16058756Scg	} while (0)
161108064Ssemenu
162108064Ssemenu	/*
163108064Ssemenu	 * Remove IPv6 Hooks
16458756Scg	 */
16558756Scg	if (ifs->ifs_ipf_ipv6 != NULL) {
16658756Scg		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in,
16758756Scg			  NH_PHYSICAL_IN, ifs_ipfhook6_in);
16858756Scg		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out,
16958756Scg			  NH_PHYSICAL_OUT, ifs_ipfhook6_out);
17058756Scg		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events,
17158756Scg			  NH_NIC_EVENTS, ifs_ipfhook6_nicevents);
17258756Scg		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in,
17358756Scg			  NH_LOOPBACK_IN, ifs_ipfhook6_loop_in);
17458756Scg		UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out,
17558756Scg			  NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out);
17658756Scg
17758756Scg		if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0)
17858756Scg			goto detach_failed;
17958756Scg		ifs->ifs_ipf_ipv6 = NULL;
18058756Scg        }
18158756Scg
18258756Scg	/*
18358756Scg	 * Remove IPv4 Hooks
18458756Scg	 */
18558756Scg	if (ifs->ifs_ipf_ipv4 != NULL) {
18658756Scg		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in,
18758756Scg			  NH_PHYSICAL_IN, ifs_ipfhook4_in);
18858756Scg		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out,
18958756Scg			  NH_PHYSICAL_OUT, ifs_ipfhook4_out);
19058756Scg		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events,
19158756Scg			  NH_NIC_EVENTS, ifs_ipfhook4_nicevents);
19258756Scg		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in,
19358756Scg			  NH_LOOPBACK_IN, ifs_ipfhook4_loop_in);
19458756Scg		UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out,
19558756Scg			  NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out);
19658756Scg
19758756Scg		if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0)
19858756Scg			goto detach_failed;
19958756Scg		ifs->ifs_ipf_ipv4 = NULL;
20058756Scg	}
20158756Scg
20258756Scg#undef UNDO_HOOK
20358756Scg
20458756Scg#ifdef	IPFDEBUG
20558756Scg	cmn_err(CE_CONT, "ipldetach()\n");
20658756Scg#endif
20758756Scg
20858756Scg	WRITE_ENTER(&ifs->ifs_ipf_global);
20958756Scg	fr_deinitialise(ifs);
21058756Scg
21158756Scg	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs);
21258756Scg	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs);
21358756Scg
21458756Scg	if (ifs->ifs_ipf_locks_done == 1) {
21558756Scg		MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock);
21658756Scg		MUTEX_DESTROY(&ifs->ifs_ipf_rw);
21758756Scg		RW_DESTROY(&ifs->ifs_ipf_tokens);
21858756Scg		RW_DESTROY(&ifs->ifs_ipf_ipidfrag);
21958756Scg		ifs->ifs_ipf_locks_done = 0;
22058756Scg	}
22158756Scg
22258756Scg	if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out ||
22358756Scg	    ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in ||
22458756Scg	    ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
22558756Scg	    ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out ||
22658756Scg	    ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out)
22758756Scg		return -1;
22858756Scg
22958756Scg	return 0;
23058756Scg
23158756Scgdetach_failed:
23258756Scg	WRITE_ENTER(&ifs->ifs_ipf_global);
23358756Scg	return -1;
23458756Scg}
23558756Scg
23658756Scgint iplattach(ifs)
23758756Scgipf_stack_t *ifs;
23858756Scg{
23958756Scg#if SOLARIS2 < 10
24058756Scg	int i;
24158756Scg#endif
24258756Scg	netid_t id = ifs->ifs_netid;
24358756Scg
24458756Scg#ifdef	IPFDEBUG
24558756Scg	cmn_err(CE_CONT, "iplattach()\n");
24658756Scg#endif
24758756Scg
24858756Scg	ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0);
24958756Scg	ifs->ifs_fr_flags = IPF_LOGGING;
25058756Scg#ifdef _KERNEL
25158756Scg	ifs->ifs_fr_update_ipid = 0;
25258756Scg#else
25358756Scg	ifs->ifs_fr_update_ipid = 1;
25458756Scg#endif
25558756Scg	ifs->ifs_fr_minttl = 4;
25658756Scg	ifs->ifs_fr_icmpminfragmtu = 68;
25758756Scg#if defined(IPFILTER_DEFAULT_BLOCK)
25858756Scg	ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
25958756Scg#else
26058756Scg	ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
26158756Scg#endif
26258756Scg
26358756Scg	MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex");
26458756Scg	MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex");
26558756Scg	RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
26658756Scg	RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock");
26758756Scg	ifs->ifs_ipf_locks_done = 1;
26858756Scg
26958756Scg	if (fr_initialise(ifs) < 0)
27058756Scg		return -1;
27158756Scg
27258756Scg	HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4,
27358756Scg		  "ipfilter_hook4_nicevents", ifs);
27458756Scg	HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in,
27558756Scg		  "ipfilter_hook4_in", ifs);
27689774Sscottl	HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out,
27758756Scg		  "ipfilter_hook4_out", ifs);
27858756Scg	HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_loop_in,
27958756Scg		  "ipfilter_hook4_loop_in", ifs);
28058756Scg	HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_loop_out,
28158756Scg		  "ipfilter_hook4_loop_out", ifs);
28258756Scg
28358756Scg	/*
28458756Scg	 * If we hold this lock over all of the net_hook_register calls, we
28558756Scg	 * can cause a deadlock to occur with the following lock ordering:
28658756Scg	 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs
28765644Scg	 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path)
28865644Scg	 */
28958756Scg	RWLOCK_EXIT(&ifs->ifs_ipf_global);
29058756Scg
29158756Scg	/*
29258756Scg	 * Add IPv4 hooks
29384111Scg	 */
29458756Scg	ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET);
29558756Scg	if (ifs->ifs_ipf_ipv4 == NULL)
29658756Scg		goto hookup_failed;
29758756Scg
29884111Scg	ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4,
29958756Scg	    NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0);
30058756Scg	if (!ifs->ifs_hook4_nic_events)
30158756Scg		goto hookup_failed;
30258756Scg
30358756Scg	ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4,
30458756Scg	    NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0);
30558756Scg	if (!ifs->ifs_hook4_physical_in)
30665644Scg		goto hookup_failed;
30765644Scg
30865644Scg	ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4,
30965644Scg	    NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0);
31065644Scg	if (!ifs->ifs_hook4_physical_out)
31158756Scg		goto hookup_failed;
31258756Scg
31358756Scg	if (ifs->ifs_ipf_loopback) {
31458756Scg		ifs->ifs_hook4_loopback_in = (net_hook_register(
31558756Scg		    ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
31658756Scg		    ifs->ifs_ipfhook4_loop_in) == 0);
31758756Scg		if (!ifs->ifs_hook4_loopback_in)
31858756Scg			goto hookup_failed;
31958756Scg
320127135Snjl		ifs->ifs_hook4_loopback_out = (net_hook_register(
321127135Snjl		    ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
32258756Scg		    ifs->ifs_ipfhook4_loop_out) == 0);
32358756Scg		if (!ifs->ifs_hook4_loopback_out)
324127135Snjl			goto hookup_failed;
325127135Snjl	}
32658756Scg	/*
32758756Scg	 * Add IPv6 hooks
328127135Snjl	 */
329127135Snjl	ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6);
33058756Scg	if (ifs->ifs_ipf_ipv6 == NULL)
33158756Scg		goto hookup_failed;
332127135Snjl
333127135Snjl	HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6,
33458756Scg		  "ipfilter_hook6_nicevents", ifs);
33558756Scg	HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in,
33658756Scg		  "ipfilter_hook6_in", ifs);
33784111Scg	HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out,
33858756Scg		  "ipfilter_hook6_out", ifs);
33958756Scg	HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_loop_in,
34058756Scg		  "ipfilter_hook6_loop_in", ifs);
34184111Scg	HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_loop_out,
34258756Scg		  "ipfilter_hook6_loop_out", ifs);
34358756Scg
34458756Scg	ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6,
34558756Scg	    NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0);
34658756Scg	if (!ifs->ifs_hook6_nic_events)
34758756Scg		goto hookup_failed;
34858756Scg
34958756Scg	ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6,
35058756Scg	    NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0);
35158756Scg	if (!ifs->ifs_hook6_physical_in)
35258756Scg		goto hookup_failed;
35358756Scg
35474763Scg	ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6,
35558756Scg	    NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0);
35658756Scg	if (!ifs->ifs_hook6_physical_out)
35758756Scg		goto hookup_failed;
35858756Scg
35958756Scg	if (ifs->ifs_ipf_loopback) {
36058756Scg		ifs->ifs_hook6_loopback_in = (net_hook_register(
36158756Scg		    ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
36258756Scg		    ifs->ifs_ipfhook6_loop_in) == 0);
36358756Scg		if (!ifs->ifs_hook6_loopback_in)
36458756Scg			goto hookup_failed;
365148598Snetchild
366148598Snetchild		ifs->ifs_hook6_loopback_out = (net_hook_register(
36770392Scg		    ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
368148598Snetchild		    ifs->ifs_ipfhook6_loop_out) == 0);
369148598Snetchild		if (!ifs->ifs_hook6_loopback_out)
37058756Scg			goto hookup_failed;
37170134Scg	}
372110499Snyan
37358756Scg	/*
37458756Scg	 * Reacquire ipf_global, now it is safe.
37558756Scg	 */
37658756Scg	WRITE_ENTER(&ifs->ifs_ipf_global);
37758756Scg
37858756Scg/* Do not use private interface ip_params_arr[] in Solaris 10 */
37958756Scg#if SOLARIS2 < 10
38058756Scg
38158756Scg#if SOLARIS2 >= 8
382148598Snetchild	ip_forwarding = &ip_g_forward;
383148598Snetchild#endif
38470392Scg	/*
385148598Snetchild	 * XXX - There is no terminator for this array, so it is not possible
386148598Snetchild	 * to tell if what we are looking for is missing and go off the end
38758756Scg	 * of the array.
38870134Scg	 */
389110499Snyan
39058756Scg#if SOLARIS2 <= 8
39158756Scg	for (i = 0; ; i++) {
39258756Scg		if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) {
39358756Scg			ip_ttl_ptr = &ip_param_arr[i].ip_param_value;
39458756Scg		} else if (!strcmp(ip_param_arr[i].ip_param_name,
39558756Scg			    "ip_path_mtu_discovery")) {
39658756Scg			ip_mtudisc = &ip_param_arr[i].ip_param_value;
39758756Scg		}
39858756Scg#if SOLARIS2 < 8
39958756Scg		else if (!strcmp(ip_param_arr[i].ip_param_name,
40074763Scg			    "ip_forwarding")) {
40158756Scg			ip_forwarding = &ip_param_arr[i].ip_param_value;
40258756Scg		}
40358756Scg#else
40458756Scg		else if (!strcmp(ip_param_arr[i].ip_param_name,
40558756Scg			    "ip6_forwarding")) {
40658756Scg			ip6_forwarding = &ip_param_arr[i].ip_param_value;
40758756Scg		}
40858756Scg#endif
40958756Scg
41058756Scg		if (ip_mtudisc != NULL && ip_ttl_ptr != NULL &&
41158756Scg#if SOLARIS2 >= 8
41258756Scg		    ip6_forwarding != NULL &&
41358756Scg#endif
41458756Scg		    ip_forwarding != NULL)
41558756Scg			break;
41658756Scg	}
41758756Scg#endif
41858756Scg
41958756Scg	if (ifs->ifs_fr_control_forwarding & 1) {
42058756Scg		if (ip_forwarding != NULL)
42158756Scg			*ip_forwarding = 1;
42258756Scg#if SOLARIS2 >= 8
42358756Scg		if (ip6_forwarding != NULL)
42458756Scg			*ip6_forwarding = 1;
42558756Scg#endif
42658756Scg	}
42758756Scg
42858756Scg#endif
42958756Scg
43058756Scg	return 0;
43158756Scghookup_failed:
43260571Scg	WRITE_ENTER(&ifs->ifs_ipf_global);
43360571Scg	return -1;
43458756Scg}
43560571Scg
43660571Scgstatic	int	fr_setipfloopback(set, ifs)
43760571Scgint set;
43858756Scgipf_stack_t *ifs;
43958756Scg{
44058756Scg	if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL)
44158756Scg		return EFAULT;
44258756Scg
44358756Scg	if (set && !ifs->ifs_ipf_loopback) {
44458756Scg		ifs->ifs_ipf_loopback = 1;
44558756Scg
44658756Scg		ifs->ifs_hook4_loopback_in = (net_hook_register(
44758756Scg		    ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
44858756Scg		    ifs->ifs_ipfhook4_loop_in) == 0);
44958756Scg		if (!ifs->ifs_hook4_loopback_in)
45058756Scg			return EINVAL;
45158756Scg
45258756Scg		ifs->ifs_hook4_loopback_out = (net_hook_register(
45358756Scg		    ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
45458756Scg		    ifs->ifs_ipfhook4_loop_out) == 0);
45558756Scg		if (!ifs->ifs_hook4_loopback_out)
45658756Scg			return EINVAL;
45758756Scg
45858756Scg		ifs->ifs_hook6_loopback_in = (net_hook_register(
45958756Scg		    ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
46058756Scg		    ifs->ifs_ipfhook6_loop_in) == 0);
46158756Scg		if (!ifs->ifs_hook6_loopback_in)
46258756Scg			return EINVAL;
46358756Scg
46458756Scg		ifs->ifs_hook6_loopback_out = (net_hook_register(
46558756Scg		    ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
46658756Scg		    ifs->ifs_ipfhook6_loop_out) == 0);
46758756Scg		if (!ifs->ifs_hook6_loopback_out)
46858756Scg			return EINVAL;
46958756Scg
47058756Scg	} else if (!set && ifs->ifs_ipf_loopback) {
47158756Scg		ifs->ifs_ipf_loopback = 0;
47258756Scg
47358756Scg		ifs->ifs_hook4_loopback_in =
47458756Scg		    (net_hook_unregister(ifs->ifs_ipf_ipv4,
47558756Scg		    NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
47658756Scg		if (ifs->ifs_hook4_loopback_in)
47758756Scg			return EBUSY;
47858756Scg
47958756Scg		ifs->ifs_hook4_loopback_out =
48058756Scg		    (net_hook_unregister(ifs->ifs_ipf_ipv4,
48158756Scg		    NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0);
48258756Scg		if (ifs->ifs_hook4_loopback_out)
48358756Scg			return EBUSY;
48458756Scg
48558756Scg		ifs->ifs_hook6_loopback_in =
48658756Scg		    (net_hook_unregister(ifs->ifs_ipf_ipv6,
48758756Scg		    NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
48858756Scg		if (ifs->ifs_hook6_loopback_in)
48958756Scg			return EBUSY;
49058756Scg
49158756Scg		ifs->ifs_hook6_loopback_out =
49258756Scg		    (net_hook_unregister(ifs->ifs_ipf_ipv6,
49358756Scg		    NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0);
49458756Scg		if (ifs->ifs_hook6_loopback_out)
49558756Scg			return EBUSY;
49658756Scg	}
49758756Scg	return 0;
49858756Scg}
49958756Scg
50058756Scg
50158756Scg/*
50258756Scg * Filter ioctl interface.
50358756Scg */
50458756Scg/*ARGSUSED*/
50558756Scgint iplioctl(dev, cmd, data, mode, cp, rp)
50658756Scgdev_t dev;
50758756Scgint cmd;
50858756Scg#if SOLARIS2 >= 7
50958756Scgintptr_t data;
51058756Scg#else
51158756Scgint *data;
51258756Scg#endif
51358756Scgint mode;
51458756Scgcred_t *cp;
51574763Scgint *rp;
51658756Scg{
51758756Scg	int error = 0, tmp;
51858756Scg	friostat_t fio;
51958756Scg	minor_t unit;
52058756Scg	u_int enable;
52158756Scg	ipf_stack_t *ifs;
52258756Scg
52358756Scg#ifdef	IPFDEBUG
52458756Scg	cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n",
52574763Scg		dev, cmd, data, mode, cp, rp);
52670291Scg#endif
52758756Scg	unit = getminor(dev);
52858756Scg	if (IPL_LOGMAX < unit)
52958756Scg		return ENXIO;
53058756Scg
53158756Scg        /*
53258756Scg	 * As we're calling ipf_find_stack in user space, from a given zone
53358756Scg	 * to find the stack pointer for this zone, there is no need to have
53474763Scg	 * a hold/refence count here.
53558756Scg	 */
53658756Scg	ifs = ipf_find_stack(crgetzoneid(cp));
53758756Scg	ASSERT(ifs != NULL);
53858756Scg
53958756Scg	if (ifs->ifs_fr_running <= 0) {
54058756Scg		if (unit != IPL_LOGIPF) {
54158756Scg			return EIO;
54258756Scg		}
54358756Scg		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
54474763Scg		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
54558756Scg		    cmd != SIOCGETFS && cmd != SIOCGETFF) {
54658756Scg			return EIO;
54758756Scg		}
54858756Scg	}
54958756Scg
55058756Scg	READ_ENTER(&ifs->ifs_ipf_global);
55158756Scg
55274763Scg	error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid,
55358756Scg			       curproc, ifs);
55458756Scg	if (error != -1) {
55558756Scg		RWLOCK_EXIT(&ifs->ifs_ipf_global);
55670134Scg		return error;
55758756Scg	}
55858756Scg	error = 0;
55974763Scg
56058756Scg	switch (cmd)
56158756Scg	{
56258756Scg	case SIOCFRENB :
56358756Scg		if (!(mode & FWRITE))
56458756Scg			error = EPERM;
56558756Scg		else {
56658756Scg			error = COPYIN((caddr_t)data, (caddr_t)&enable,
567168847Sariff				       sizeof(enable));
56858756Scg			if (error != 0) {
56965644Scg				error = EFAULT;
57058756Scg				break;
57158756Scg			}
57258756Scg
573110499Snyan			RWLOCK_EXIT(&ifs->ifs_ipf_global);
57458756Scg			WRITE_ENTER(&ifs->ifs_ipf_global);
57558756Scg			error = fr_enableipf(ifs, enable);
57658756Scg		}
57758756Scg		break;
57870134Scg	case SIOCIPFSET :
57958756Scg		if (!(mode & FWRITE)) {
58058756Scg			error = EPERM;
58158756Scg			break;
58258756Scg		}
58358756Scg		/* FALLTHRU */
58458756Scg	case SIOCIPFGETNEXT :
58558756Scg	case SIOCIPFGET :
58658756Scg		error = fr_ipftune(cmd, (void *)data, ifs);
58770134Scg		break;
58858756Scg	case SIOCSETFF :
58958756Scg		if (!(mode & FWRITE))
59058756Scg			error = EPERM;
59158756Scg		else {
59258756Scg			error = COPYIN((caddr_t)data,
59358756Scg				       (caddr_t)&ifs->ifs_fr_flags,
59458756Scg				       sizeof(ifs->ifs_fr_flags));
59558756Scg			if (error != 0)
59658756Scg				error = EFAULT;
59758756Scg		}
59858756Scg		break;
59958756Scg	case SIOCIPFLP :
60058756Scg		error = COPYIN((caddr_t)data, (caddr_t)&tmp,
60170134Scg			       sizeof(tmp));
60258756Scg		if (error != 0)
60370291Scg			error = EFAULT;
60470291Scg		else
60570291Scg			error = fr_setipfloopback(tmp, ifs);
60670291Scg		break;
60758756Scg	case SIOCGETFF :
60858756Scg		error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data,
60958756Scg				sizeof(ifs->ifs_fr_flags));
61070134Scg		if (error != 0)
61158756Scg			error = EFAULT;
61258756Scg		break;
61358756Scg	case SIOCFUNCL :
61460958Scg		error = fr_resolvefunc((void *)data);
61558756Scg		break;
61658756Scg	case SIOCINAFR :
61758756Scg	case SIOCRMAFR :
61858756Scg	case SIOCADAFR :
61970134Scg	case SIOCZRLST :
620110499Snyan		if (!(mode & FWRITE))
62158756Scg			error = EPERM;
62258756Scg		else
62358756Scg			error = frrequest(unit, cmd, (caddr_t)data,
62458756Scg					  ifs->ifs_fr_active, 1, ifs);
62558756Scg		break;
62658756Scg	case SIOCINIFR :
62758756Scg	case SIOCRMIFR :
62858756Scg	case SIOCADIFR :
62958756Scg		if (!(mode & FWRITE))
63058756Scg			error = EPERM;
63158756Scg		else
63258756Scg			error = frrequest(unit, cmd, (caddr_t)data,
63358756Scg					  1 - ifs->ifs_fr_active, 1, ifs);
63470134Scg		break;
63558756Scg	case SIOCSWAPA :
63658756Scg		if (!(mode & FWRITE))
63758756Scg			error = EPERM;
638110499Snyan		else {
63958756Scg			WRITE_ENTER(&ifs->ifs_ipf_mutex);
64058756Scg			error = COPYOUT((caddr_t)&ifs->ifs_fr_active,
64174763Scg					(caddr_t)data,
64270134Scg					sizeof(ifs->ifs_fr_active));
64358756Scg			if (error != 0)
64458756Scg				error = EFAULT;
64558756Scg			else
64658756Scg				ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
64758756Scg			RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
64858756Scg		}
64970134Scg		break;
65070134Scg	case SIOCGETFS :
65170134Scg		fr_getstat(&fio, ifs);
65270134Scg		error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
65370134Scg		break;
65470134Scg	case SIOCFRZST :
65570134Scg		if (!(mode & FWRITE))
65670134Scg			error = EPERM;
65770134Scg		else
65870134Scg			error = fr_zerostats((caddr_t)data, ifs);
65970134Scg		break;
66070134Scg	case	SIOCIPFFL :
66158756Scg		if (!(mode & FWRITE))
66258756Scg			error = EPERM;
66358756Scg		else {
66474763Scg			error = COPYIN((caddr_t)data, (caddr_t)&tmp,
66558756Scg				       sizeof(tmp));
66658756Scg			if (!error) {
66758756Scg				tmp = frflush(unit, 4, tmp, ifs);
66858756Scg				error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
66958756Scg						sizeof(tmp));
67058756Scg				if (error != 0)
67158756Scg					error = EFAULT;
67258756Scg			} else
67373151Scg				error = EFAULT;
67458756Scg		}
67558756Scg		break;
67658756Scg#ifdef USE_INET6
67758756Scg	case	SIOCIPFL6 :
67858756Scg		if (!(mode & FWRITE))
67958756Scg			error = EPERM;
68058756Scg		else {
68174763Scg			error = COPYIN((caddr_t)data, (caddr_t)&tmp,
68258756Scg				       sizeof(tmp));
68358756Scg			if (!error) {
68458756Scg				tmp = frflush(unit, 6, tmp, ifs);
68558756Scg				error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
68658756Scg						sizeof(tmp));
68758756Scg				if (error != 0)
68858756Scg					error = EFAULT;
68958756Scg			} else
69058756Scg				error = EFAULT;
69158756Scg		}
69258756Scg		break;
69358756Scg#endif
69458756Scg	case SIOCSTLCK :
69558756Scg		error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
69658756Scg		if (error == 0) {
69758756Scg			ifs->ifs_fr_state_lock = tmp;
69858756Scg			ifs->ifs_fr_nat_lock = tmp;
69958756Scg			ifs->ifs_fr_frag_lock = tmp;
70058756Scg			ifs->ifs_fr_auth_lock = tmp;
70158756Scg		} else
70258756Scg			error = EFAULT;
70358756Scg	break;
70458756Scg#ifdef	IPFILTER_LOG
70558756Scg	case	SIOCIPFFB :
70658756Scg		if (!(mode & FWRITE))
70758756Scg			error = EPERM;
70858756Scg		else {
70958756Scg			tmp = ipflog_clear(unit, ifs);
71058756Scg			error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
71158756Scg				       sizeof(tmp));
71258756Scg			if (error)
71358756Scg				error = EFAULT;
71458756Scg		}
71558756Scg		break;
71658756Scg#endif /* IPFILTER_LOG */
71758756Scg	case SIOCFRSYN :
71858756Scg		if (!(mode & FWRITE))
71973151Scg			error = EPERM;
72073151Scg		else {
72173151Scg			RWLOCK_EXIT(&ifs->ifs_ipf_global);
72273151Scg			WRITE_ENTER(&ifs->ifs_ipf_global);
72373151Scg
72458756Scg			frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
72558756Scg			fr_natifpsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
72658756Scg			fr_nataddrsync(0, NULL, NULL, ifs);
72758756Scg			fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs);
72858756Scg			error = 0;
72958756Scg		}
73058756Scg		break;
73158756Scg	case SIOCGFRST :
73258756Scg		error = fr_outobj((void *)data, fr_fragstats(ifs),
73358756Scg				  IPFOBJ_FRAGSTAT);
73458756Scg		break;
73558756Scg	case FIONREAD :
73658756Scg#ifdef	IPFILTER_LOG
73758756Scg		tmp = (int)ifs->ifs_iplused[IPL_LOGIPF];
73858756Scg
73958756Scg		error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp));
74058756Scg		if (error != 0)
74158756Scg			error = EFAULT;
74258756Scg#endif
74358756Scg		break;
74458756Scg	case SIOCIPFITER :
74574763Scg		error = ipf_frruleiter((caddr_t)data, cp->cr_uid,
74658756Scg				       curproc, ifs);
74758756Scg		break;
74858756Scg
74958756Scg	case SIOCGENITER :
75058756Scg		error = ipf_genericiter((caddr_t)data, cp->cr_uid,
75158756Scg					curproc, ifs);
75258756Scg		break;
75358756Scg
75458756Scg	case SIOCIPFDELTOK :
75558756Scg		error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp));
75658756Scg		if (error != 0) {
75758756Scg			error = EFAULT;
75858756Scg		} else {
75958756Scg			error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs);
76058756Scg		}
76158756Scg		break;
76258756Scg
76358756Scg	default :
76458756Scg		cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p",
76558756Scg			cmd, (void *)data);
76658756Scg		error = EINVAL;
76758756Scg		break;
76858756Scg	}
76958756Scg	RWLOCK_EXIT(&ifs->ifs_ipf_global);
77058756Scg	return error;
77158756Scg}
77258756Scg
77358756Scg
77458756Scgstatic int fr_enableipf(ifs, enable)
77570134Scgipf_stack_t *ifs;
77670134Scgint enable;
77770134Scg{
77870134Scg	int error;
77970134Scg
78070134Scg	if (!enable) {
78170134Scg		error = ipldetach(ifs);
78270134Scg		if (error == 0)
78370134Scg			ifs->ifs_fr_running = -1;
78470134Scg		return error;
78558756Scg	}
78658756Scg
78758756Scg	if (ifs->ifs_fr_running > 0)
78858756Scg		return 0;
78958756Scg
79058756Scg	error = iplattach(ifs);
79158756Scg	if (error == 0) {
79258756Scg		if (ifs->ifs_fr_timer_id == NULL) {
79358756Scg			int hz = drv_usectohz(500000);
79458756Scg
79558756Scg			ifs->ifs_fr_timer_id = timeout(fr_slowtimer,
79658756Scg						       (void *)ifs,
79758756Scg						       hz);
79858756Scg		}
79958756Scg		ifs->ifs_fr_running = 1;
80058756Scg	} else {
80158756Scg		(void) ipldetach(ifs);
80258756Scg	}
80358756Scg	return error;
80458756Scg}
80558756Scg
80658756Scg
80758756Scgphy_if_t get_unit(name, v, ifs)
80858756Scgchar *name;
80970134Scgint v;
81070134Scgipf_stack_t *ifs;
81158756Scg{
81278564Sgreid	net_handle_t nif;
81358756Scg
81458756Scg  	if (v == 4)
81558756Scg 		nif = ifs->ifs_ipf_ipv4;
81674763Scg  	else if (v == 6)
81784111Scg 		nif = ifs->ifs_ipf_ipv6;
81870134Scg  	else
81970134Scg 		return 0;
82070134Scg
82170134Scg 	return (net_phylookup(nif, name));
82270134Scg}
82370134Scg
82470134Scg/*
82570134Scg * routines below for saving IP headers to buffer
82670134Scg */
82770134Scg/*ARGSUSED*/
82870134Scgint iplopen(devp, flags, otype, cred)
82970134Scgdev_t *devp;
83070134Scgint flags, otype;
83170134Scgcred_t *cred;
83270134Scg{
83370134Scg	minor_t min = getminor(*devp);
83470134Scg
83570134Scg#ifdef	IPFDEBUG
83670134Scg	cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred);
83770134Scg#endif
83870134Scg	if (!(otype & OTYP_CHR))
83970134Scg		return ENXIO;
84070134Scg
84170134Scg	min = (IPL_LOGMAX < min) ? ENXIO : 0;
84270134Scg	return min;
84370134Scg}
84470134Scg
84570134Scg
84670134Scg/*ARGSUSED*/
84770134Scgint iplclose(dev, flags, otype, cred)
84870134Scgdev_t dev;
84970134Scgint flags, otype;
85070134Scgcred_t *cred;
851128232Sgreen{
85270134Scg	minor_t	min = getminor(dev);
85370134Scg
85470134Scg#ifdef	IPFDEBUG
855166904Snetchild	cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred);
856166904Snetchild#endif
85770134Scg
85870134Scg	min = (IPL_LOGMAX < min) ? ENXIO : 0;
85970134Scg	return min;
86084111Scg}
86170134Scg
862117126Sscottl#ifdef	IPFILTER_LOG
863117126Sscottl/*
86470134Scg * iplread/ipllog
86570134Scg * both of these must operate with at least splnet() lest they be
86670134Scg * called during packet processing and cause an inconsistancy to appear in
86770134Scg * the filter lists.
86870134Scg */
86984111Scg/*ARGSUSED*/
87084111Scgint iplread(dev, uio, cp)
87184111Scgdev_t dev;
87270134Scgregister struct uio *uio;
873126695Smatkcred_t *cp;
87484111Scg{
875126695Smatk	ipf_stack_t *ifs;
876126695Smatk	int ret;
87784111Scg
87870134Scg        /*
87970134Scg	 * As we're calling ipf_find_stack in user space, from a given zone
88070134Scg	 * to find the stack pointer for this zone, there is no need to have
88170134Scg	 * a hold/refence count here.
88270134Scg	 */
88370134Scg	ifs = ipf_find_stack(crgetzoneid(cp));
88470134Scg	ASSERT(ifs != NULL);
88570134Scg
88670134Scg# ifdef	IPFDEBUG
88770134Scg	cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp);
88870134Scg# endif
88958756Scg
89058756Scg	if (ifs->ifs_fr_running < 1) {
89170134Scg		return EIO;
89270134Scg	}
89370134Scg
89470134Scg# ifdef	IPFILTER_SYNC
89570134Scg	if (getminor(dev) == IPL_LOGSYNC) {
89670134Scg		return ipfsync_read(uio);
89770134Scg	}
89870134Scg# endif
89970134Scg
90070134Scg	ret = ipflog_read(getminor(dev), uio, ifs);
90170134Scg	return ret;
90270134Scg}
90370134Scg#endif /* IPFILTER_LOG */
90470134Scg
90570134Scg
90675326Sgreid/*
90775326Sgreid * iplread/ipllog
90875326Sgreid * both of these must operate with at least splnet() lest they be
90975326Sgreid * called during packet processing and cause an inconsistancy to appear in
91075326Sgreid * the filter lists.
91175326Sgreid */
91275326Sgreidint iplwrite(dev, uio, cp)
91375326Sgreiddev_t dev;
91475326Sgreidregister struct uio *uio;
91575326Sgreidcred_t *cp;
91675326Sgreid{
91775326Sgreid	ipf_stack_t *ifs;
91875326Sgreid
91975326Sgreid        /*
92075326Sgreid	 * As we're calling ipf_find_stack in user space, from a given zone
92175326Sgreid	 * to find the stack pointer for this zone, there is no need to have
92275326Sgreid	 * a hold/refence count here.
92375326Sgreid	 */
92475326Sgreid	ifs = ipf_find_stack(crgetzoneid(cp));
92575326Sgreid	ASSERT(ifs != NULL);
92658756Scg
92758756Scg#ifdef	IPFDEBUG
92858756Scg	cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp);
92958756Scg#endif
93065644Scg
93175326Sgreid	if (ifs->ifs_fr_running < 1) {
93258756Scg		return EIO;
93358756Scg	}
93458756Scg
93558756Scg#ifdef	IPFILTER_SYNC
93658756Scg	if (getminor(dev) == IPL_LOGSYNC)
93758756Scg		return ipfsync_write(uio);
93858756Scg#endif /* IPFILTER_SYNC */
93982180Scg	dev = dev;	/* LINT */
94058756Scg	uio = uio;	/* LINT */
94158756Scg	cp = cp;	/* LINT */
94262483Scg	return ENXIO;
943132236Stanimura}
94474763Scg
94562483Scg
94658756Scg/*
94770134Scg * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
94862483Scg * requires a large amount of setting up and isn't any more efficient.
94958756Scg */
95058756Scgint fr_send_reset(fin)
95158756Scgfr_info_t *fin;
95258756Scg{
95358756Scg	tcphdr_t *tcp, *tcp2;
95458756Scg	int tlen, hlen;
95558756Scg	mblk_t *m;
95658756Scg#ifdef	USE_INET6
95758756Scg	ip6_t *ip6;
95858756Scg#endif
95971932Scg	ip_t *ip;
96071932Scg
96171932Scg	tcp = fin->fin_dp;
96271932Scg	if (tcp->th_flags & TH_RST)
96371932Scg		return -1;
96471932Scg
96558756Scg#ifndef	IPFILTER_CKSUM
96658756Scg	if (fr_checkl4sum(fin) == -1)
96758756Scg		return -1;
96858756Scg#endif
96958756Scg
97058756Scg	tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0;
97158756Scg#ifdef	USE_INET6
97258756Scg	if (fin->fin_v == 6)
97358756Scg		hlen = sizeof(ip6_t);
97458756Scg	else
975127135Snjl#endif
97658756Scg		hlen = sizeof(ip_t);
97758756Scg	hlen += sizeof(*tcp2);
97858756Scg	if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL)
97958756Scg		return -1;
98058756Scg
98158756Scg	m->b_rptr += 64;
98258756Scg	MTYPE(m) = M_DATA;
98358756Scg	m->b_wptr = m->b_rptr + hlen;
98458756Scg	ip = (ip_t *)m->b_rptr;
98558756Scg	bzero((char *)ip, hlen);
98658756Scg	tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2));
98758756Scg	tcp2->th_dport = tcp->th_sport;
98858756Scg	tcp2->th_sport = tcp->th_dport;
98958756Scg	if (tcp->th_flags & TH_ACK) {
99058756Scg		tcp2->th_seq = tcp->th_ack;
99158756Scg		tcp2->th_flags = TH_RST;
99258756Scg	} else {
99365644Scg		tcp2->th_ack = ntohl(tcp->th_seq);
99465644Scg		tcp2->th_ack += tlen;
99565644Scg		tcp2->th_ack = htonl(tcp2->th_ack);
99665644Scg		tcp2->th_flags = TH_RST|TH_ACK;
99765644Scg	}
99865644Scg	tcp2->th_off = sizeof(struct tcphdr) >> 2;
99958756Scg
100058756Scg	ip->ip_v = fin->fin_v;
100158756Scg#ifdef	USE_INET6
100258756Scg	if (fin->fin_v == 6) {
100365644Scg		ip6 = (ip6_t *)m->b_rptr;
100458756Scg		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
100558756Scg		ip6->ip6_src = fin->fin_dst6.in6;
100658756Scg		ip6->ip6_dst = fin->fin_src6.in6;
100758756Scg		ip6->ip6_plen = htons(sizeof(*tcp));
100858756Scg		ip6->ip6_nxt = IPPROTO_TCP;
100958756Scg		tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2);
101058756Scg	} else
101182180Scg#endif
101258756Scg	{
101358756Scg		ip->ip_src.s_addr = fin->fin_daddr;
101458756Scg		ip->ip_dst.s_addr = fin->fin_saddr;
1015136410Snjl		ip->ip_id = fr_nextipid(fin);
1016		ip->ip_hl = sizeof(*ip) >> 2;
1017		ip->ip_p = IPPROTO_TCP;
1018		ip->ip_len = sizeof(*ip) + sizeof(*tcp);
1019		ip->ip_tos = fin->fin_ip->ip_tos;
1020		tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2);
1021	}
1022	return fr_send_ip(fin, m, &m);
1023}
1024
1025/*
1026 * Function:	fr_send_ip
1027 * Returns:	 0: success
1028 *		-1: failed
1029 * Parameters:
1030 *	fin: packet information
1031 *	m: the message block where ip head starts
1032 *
1033 * Send a new packet through the IP stack.
1034 *
1035 * For IPv4 packets, ip_len must be in host byte order, and ip_v,
1036 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this
1037 * function).
1038 *
1039 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled
1040 * in by this function.
1041 *
1042 * All other portions of the packet must be in on-the-wire format.
1043 */
1044/*ARGSUSED*/
1045static int fr_send_ip(fin, m, mpp)
1046fr_info_t *fin;
1047mblk_t *m, **mpp;
1048{
1049	qpktinfo_t qpi, *qpip;
1050	fr_info_t fnew;
1051	ip_t *ip;
1052	int i, hlen;
1053	ipf_stack_t *ifs = fin->fin_ifs;
1054
1055	ip = (ip_t *)m->b_rptr;
1056	bzero((char *)&fnew, sizeof(fnew));
1057
1058#ifdef	USE_INET6
1059	if (fin->fin_v == 6) {
1060		ip6_t *ip6;
1061
1062		ip6 = (ip6_t *)ip;
1063		ip6->ip6_vfc = 0x60;
1064		ip6->ip6_hlim = 127;
1065		fnew.fin_v = 6;
1066		hlen = sizeof(*ip6);
1067		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
1068	} else
1069#endif
1070	{
1071		fnew.fin_v = 4;
1072#if SOLARIS2 >= 10
1073		ip->ip_ttl = 255;
1074		if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1)
1075			ip->ip_off = htons(IP_DF);
1076#else
1077		if (ip_ttl_ptr != NULL)
1078			ip->ip_ttl = (u_char)(*ip_ttl_ptr);
1079		else
1080			ip->ip_ttl = 63;
1081		if (ip_mtudisc != NULL)
1082			ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0);
1083		else
1084			ip->ip_off = htons(IP_DF);
1085#endif
1086		/*
1087		 * The dance with byte order and ip_len/ip_off is because in
1088		 * fr_fastroute, it expects them to be in host byte order but
1089		 * ipf_cksum expects them to be in network byte order.
1090		 */
1091		ip->ip_len = htons(ip->ip_len);
1092		ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
1093		ip->ip_len = ntohs(ip->ip_len);
1094		ip->ip_off = ntohs(ip->ip_off);
1095		hlen = sizeof(*ip);
1096		fnew.fin_plen = ip->ip_len;
1097	}
1098
1099	qpip = fin->fin_qpi;
1100	qpi.qpi_off = 0;
1101	qpi.qpi_ill = qpip->qpi_ill;
1102	qpi.qpi_m = m;
1103	qpi.qpi_data = ip;
1104	fnew.fin_qpi = &qpi;
1105	fnew.fin_ifp = fin->fin_ifp;
1106	fnew.fin_flx = FI_NOCKSUM;
1107	fnew.fin_m = m;
1108	fnew.fin_qfm = m;
1109	fnew.fin_ip = ip;
1110	fnew.fin_mp = mpp;
1111	fnew.fin_hlen = hlen;
1112	fnew.fin_dp = (char *)ip + hlen;
1113	fnew.fin_ifs = fin->fin_ifs;
1114	(void) fr_makefrip(hlen, ip, &fnew);
1115
1116	i = fr_fastroute(m, mpp, &fnew, NULL);
1117	return i;
1118}
1119
1120
1121int fr_send_icmp_err(type, fin, dst)
1122int type;
1123fr_info_t *fin;
1124int dst;
1125{
1126	struct in_addr dst4;
1127	struct icmp *icmp;
1128	qpktinfo_t *qpi;
1129	int hlen, code;
1130	phy_if_t phy;
1131	u_short sz;
1132#ifdef	USE_INET6
1133	mblk_t *mb;
1134#endif
1135	mblk_t *m;
1136#ifdef	USE_INET6
1137	ip6_t *ip6;
1138#endif
1139	ip_t *ip;
1140	ipf_stack_t *ifs = fin->fin_ifs;
1141
1142	if ((type < 0) || (type > ICMP_MAXTYPE))
1143		return -1;
1144
1145	code = fin->fin_icode;
1146#ifdef USE_INET6
1147	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
1148		return -1;
1149#endif
1150
1151#ifndef	IPFILTER_CKSUM
1152	if (fr_checkl4sum(fin) == -1)
1153		return -1;
1154#endif
1155
1156	qpi = fin->fin_qpi;
1157
1158#ifdef	USE_INET6
1159	mb = fin->fin_qfm;
1160
1161	if (fin->fin_v == 6) {
1162		sz = sizeof(ip6_t);
1163		sz += MIN(mb->b_wptr - mb->b_rptr, 512);
1164		hlen = sizeof(ip6_t);
1165		type = icmptoicmp6types[type];
1166		if (type == ICMP6_DST_UNREACH)
1167			code = icmptoicmp6unreach[code];
1168	} else
1169#endif
1170	{
1171		if ((fin->fin_p == IPPROTO_ICMP) &&
1172		    !(fin->fin_flx & FI_SHORT))
1173			switch (ntohs(fin->fin_data[0]) >> 8)
1174			{
1175			case ICMP_ECHO :
1176			case ICMP_TSTAMP :
1177			case ICMP_IREQ :
1178			case ICMP_MASKREQ :
1179				break;
1180			default :
1181				return 0;
1182			}
1183
1184		sz = sizeof(ip_t) * 2;
1185		sz += 8;		/* 64 bits of data */
1186		hlen = sizeof(ip_t);
1187	}
1188
1189	sz += offsetof(struct icmp, icmp_ip);
1190	if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL)
1191		return -1;
1192	MTYPE(m) = M_DATA;
1193	m->b_rptr += 64;
1194	m->b_wptr = m->b_rptr + sz;
1195	bzero((char *)m->b_rptr, (size_t)sz);
1196	ip = (ip_t *)m->b_rptr;
1197	ip->ip_v = fin->fin_v;
1198	icmp = (struct icmp *)(m->b_rptr + hlen);
1199	icmp->icmp_type = type & 0xff;
1200	icmp->icmp_code = code & 0xff;
1201	phy = (phy_if_t)qpi->qpi_ill;
1202	if (type == ICMP_UNREACH && (phy != 0) &&
1203	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG)
1204		icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 );
1205
1206#ifdef	USE_INET6
1207	if (fin->fin_v == 6) {
1208		struct in6_addr dst6;
1209		int csz;
1210
1211		if (dst == 0) {
1212			ipf_stack_t *ifs = fin->fin_ifs;
1213
1214			if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy,
1215				       (void *)&dst6, NULL, ifs) == -1) {
1216				FREE_MB_T(m);
1217				return -1;
1218			}
1219		} else
1220			dst6 = fin->fin_dst6.in6;
1221
1222		csz = sz;
1223		sz -= sizeof(ip6_t);
1224		ip6 = (ip6_t *)m->b_rptr;
1225		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
1226		ip6->ip6_plen = htons((u_short)sz);
1227		ip6->ip6_nxt = IPPROTO_ICMPV6;
1228		ip6->ip6_src = dst6;
1229		ip6->ip6_dst = fin->fin_src6.in6;
1230		sz -= offsetof(struct icmp, icmp_ip);
1231		bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz);
1232		icmp->icmp_cksum = csz - sizeof(ip6_t);
1233	} else
1234#endif
1235	{
1236		ip->ip_hl = sizeof(*ip) >> 2;
1237		ip->ip_p = IPPROTO_ICMP;
1238		ip->ip_id = fin->fin_ip->ip_id;
1239		ip->ip_tos = fin->fin_ip->ip_tos;
1240		ip->ip_len = (u_short)sz;
1241		if (dst == 0) {
1242			ipf_stack_t *ifs = fin->fin_ifs;
1243
1244			if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy,
1245				       (void *)&dst4, NULL, ifs) == -1) {
1246				FREE_MB_T(m);
1247				return -1;
1248			}
1249		} else {
1250			dst4 = fin->fin_dst;
1251		}
1252		ip->ip_src = dst4;
1253		ip->ip_dst = fin->fin_src;
1254		bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip,
1255		      sizeof(*fin->fin_ip));
1256		bcopy((char *)fin->fin_ip + fin->fin_hlen,
1257		      (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8);
1258		icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len);
1259		icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off);
1260		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1261					     sz - sizeof(ip_t));
1262	}
1263
1264	/*
1265	 * Need to exit out of these so we don't recursively call rw_enter
1266	 * from fr_qout.
1267	 */
1268	return fr_send_ip(fin, m, &m);
1269}
1270
1271#include <sys/time.h>
1272#include <sys/varargs.h>
1273
1274#ifndef _KERNEL
1275#include <stdio.h>
1276#endif
1277
1278#define	NULLADDR_RATE_LIMIT 10	/* 10 seconds */
1279
1280
1281/*
1282 * Print out warning message at rate-limited speed.
1283 */
1284static void rate_limit_message(ipf_stack_t *ifs,
1285			       int rate, const char *message, ...)
1286{
1287	static time_t last_time = 0;
1288	time_t now;
1289	va_list args;
1290	char msg_buf[256];
1291	int  need_printed = 0;
1292
1293	now = ddi_get_time();
1294
1295	/* make sure, no multiple entries */
1296	ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk)));
1297	MUTEX_ENTER(&ifs->ifs_ipf_rw);
1298	if (now - last_time >= rate) {
1299		need_printed = 1;
1300		last_time = now;
1301	}
1302	MUTEX_EXIT(&ifs->ifs_ipf_rw);
1303
1304	if (need_printed) {
1305		va_start(args, message);
1306		(void)vsnprintf(msg_buf, 255, message, args);
1307		va_end(args);
1308#ifdef _KERNEL
1309		cmn_err(CE_WARN, msg_buf);
1310#else
1311		fprintf(std_err, msg_buf);
1312#endif
1313	}
1314}
1315
1316/*
1317 * return the first IP Address associated with an interface
1318 */
1319/*ARGSUSED*/
1320int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
1321int v, atype;
1322void *ifptr;
1323struct in_addr  *inp, *inpmask;
1324ipf_stack_t *ifs;
1325{
1326	struct sockaddr_in6 v6addr[2];
1327	struct sockaddr_in v4addr[2];
1328	net_ifaddr_t type[2];
1329	net_handle_t net_data;
1330	phy_if_t phyif;
1331	void *array;
1332
1333	switch (v)
1334	{
1335	case 4:
1336		net_data = ifs->ifs_ipf_ipv4;
1337		array = v4addr;
1338		break;
1339	case 6:
1340		net_data = ifs->ifs_ipf_ipv6;
1341		array = v6addr;
1342		break;
1343	default:
1344		net_data = NULL;
1345		break;
1346	}
1347
1348	if (net_data == NULL)
1349		return -1;
1350
1351	phyif = (phy_if_t)ifptr;
1352
1353	switch (atype)
1354	{
1355	case FRI_PEERADDR :
1356		type[0] = NA_PEER;
1357		break;
1358
1359	case FRI_BROADCAST :
1360		type[0] = NA_BROADCAST;
1361		break;
1362
1363	default :
1364		type[0] = NA_ADDRESS;
1365		break;
1366	}
1367
1368	type[1] = NA_NETMASK;
1369
1370	if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0)
1371		return -1;
1372
1373	if (v == 6) {
1374		return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1],
1375					inp, inpmask);
1376	}
1377	return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask);
1378}
1379
1380
1381u_32_t fr_newisn(fin)
1382fr_info_t *fin;
1383{
1384	static int iss_seq_off = 0;
1385	u_char hash[16];
1386	u_32_t newiss;
1387	MD5_CTX ctx;
1388	ipf_stack_t *ifs = fin->fin_ifs;
1389
1390	/*
1391	 * Compute the base value of the ISS.  It is a hash
1392	 * of (saddr, sport, daddr, dport, secret).
1393	 */
1394	MD5Init(&ctx);
1395
1396	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1397		  sizeof(fin->fin_fi.fi_src));
1398	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1399		  sizeof(fin->fin_fi.fi_dst));
1400	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1401
1402	MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret));
1403
1404	MD5Final(hash, &ctx);
1405
1406	bcopy(hash, &newiss, sizeof(newiss));
1407
1408	/*
1409	 * Now increment our "timer", and add it in to
1410	 * the computed value.
1411	 *
1412	 * XXX Use `addin'?
1413	 * XXX TCP_ISSINCR too large to use?
1414	 */
1415	iss_seq_off += 0x00010000;
1416	newiss += iss_seq_off;
1417	return newiss;
1418}
1419
1420
1421/* ------------------------------------------------------------------------ */
1422/* Function:    fr_nextipid                                                 */
1423/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1424/* Parameters:  fin(I) - pointer to packet information                      */
1425/*                                                                          */
1426/* Returns the next IPv4 ID to use for this packet.                         */
1427/* ------------------------------------------------------------------------ */
1428u_short fr_nextipid(fin)
1429fr_info_t *fin;
1430{
1431	static u_short ipid = 0;
1432	ipstate_t *is;
1433	nat_t *nat;
1434	u_short id;
1435	ipf_stack_t *ifs = fin->fin_ifs;
1436
1437	MUTEX_ENTER(&ifs->ifs_ipf_rw);
1438	if (fin->fin_state != NULL) {
1439		is = fin->fin_state;
1440		id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff);
1441	} else if (fin->fin_nat != NULL) {
1442		nat = fin->fin_nat;
1443		id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff);
1444	} else
1445		id = ipid++;
1446	MUTEX_EXIT(&ifs->ifs_ipf_rw);
1447
1448	return id;
1449}
1450
1451
1452#ifndef IPFILTER_CKSUM
1453/* ARGSUSED */
1454#endif
1455INLINE void fr_checkv4sum(fin)
1456fr_info_t *fin;
1457{
1458#ifdef IPFILTER_CKSUM
1459	if (fr_checkl4sum(fin) == -1)
1460		fin->fin_flx |= FI_BAD;
1461#endif
1462}
1463
1464
1465#ifdef USE_INET6
1466# ifndef IPFILTER_CKSUM
1467/* ARGSUSED */
1468# endif
1469INLINE void fr_checkv6sum(fin)
1470fr_info_t *fin;
1471{
1472# ifdef IPFILTER_CKSUM
1473	if (fr_checkl4sum(fin) == -1)
1474		fin->fin_flx |= FI_BAD;
1475# endif
1476}
1477#endif /* USE_INET6 */
1478
1479
1480#if (SOLARIS2 < 7)
1481void fr_slowtimer()
1482#else
1483/*ARGSUSED*/
1484void fr_slowtimer __P((void *arg))
1485#endif
1486{
1487	ipf_stack_t *ifs = arg;
1488
1489	READ_ENTER(&ifs->ifs_ipf_global);
1490	if (ifs->ifs_fr_running != 1) {
1491		ifs->ifs_fr_timer_id = NULL;
1492		RWLOCK_EXIT(&ifs->ifs_ipf_global);
1493		return;
1494	}
1495	ipf_expiretokens(ifs);
1496	fr_fragexpire(ifs);
1497	fr_timeoutstate(ifs);
1498	fr_natexpire(ifs);
1499	fr_authexpire(ifs);
1500	ifs->ifs_fr_ticks++;
1501	if (ifs->ifs_fr_running == 1)
1502		ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg,
1503		    drv_usectohz(500000));
1504	else
1505		ifs->ifs_fr_timer_id = NULL;
1506	RWLOCK_EXIT(&ifs->ifs_ipf_global);
1507}
1508
1509
1510/* ------------------------------------------------------------------------ */
1511/* Function:    fr_pullup                                                   */
1512/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1513/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1514/*              fin(I) - pointer to packet information                      */
1515/*              len(I) - number of bytes to pullup                          */
1516/*                                                                          */
1517/* Attempt to move at least len bytes (from the start of the buffer) into a */
1518/* single buffer for ease of access.  Operating system native functions are */
1519/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1520/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1521/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1522/* and ONLY if the pullup succeeds.                                         */
1523/*                                                                          */
1524/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1525/* of buffers that starts at *fin->fin_mp.                                  */
1526/* ------------------------------------------------------------------------ */
1527void *fr_pullup(min, fin, len)
1528mb_t *min;
1529fr_info_t *fin;
1530int len;
1531{
1532	qpktinfo_t *qpi = fin->fin_qpi;
1533	int out = fin->fin_out, dpoff, ipoff;
1534	mb_t *m = min, *m1, *m2;
1535	char *ip;
1536	uint32_t start, stuff, end, value, flags;
1537	ipf_stack_t *ifs = fin->fin_ifs;
1538
1539	if (m == NULL)
1540		return NULL;
1541
1542	ip = (char *)fin->fin_ip;
1543	if ((fin->fin_flx & FI_COALESCE) != 0)
1544		return ip;
1545
1546	ipoff = fin->fin_ipoff;
1547	if (fin->fin_dp != NULL)
1548		dpoff = (char *)fin->fin_dp - (char *)ip;
1549	else
1550		dpoff = 0;
1551
1552	if (M_LEN(m) < len + ipoff) {
1553
1554		/*
1555		 * pfil_precheck ensures the IP header is on a 32bit
1556		 * aligned address so simply fail if that isn't currently
1557		 * the case (should never happen).
1558		 */
1559		int inc = 0;
1560
1561		if (ipoff > 0) {
1562			if ((ipoff & 3) != 0) {
1563				inc = 4 - (ipoff & 3);
1564				if (m->b_rptr - inc >= m->b_datap->db_base)
1565					m->b_rptr -= inc;
1566				else
1567					inc = 0;
1568			}
1569		}
1570
1571		/*
1572		 * XXX This is here as a work around for a bug with DEBUG
1573		 * XXX Solaris kernels.  The problem is b_prev is used by IP
1574		 * XXX code as a way to stash the phyint_index for a packet,
1575		 * XXX this doesn't get reset by IP but freeb does an ASSERT()
1576		 * XXX for both of these to be NULL.  See 6442390.
1577		 */
1578		m1 = m;
1579		m2 = m->b_prev;
1580
1581		do {
1582			m1->b_next = NULL;
1583			m1->b_prev = NULL;
1584			m1 = m1->b_cont;
1585		} while (m1);
1586
1587		/*
1588		 * Need to preserve checksum information by copying them
1589		 * to newmp which heads the pulluped message.
1590		 */
1591		hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end,
1592		    &value, &flags);
1593
1594		if (pullupmsg(m, len + ipoff + inc) == 0) {
1595			ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]);
1596			FREE_MB_T(*fin->fin_mp);
1597			*fin->fin_mp = NULL;
1598			fin->fin_m = NULL;
1599			fin->fin_ip = NULL;
1600			fin->fin_dp = NULL;
1601			qpi->qpi_data = NULL;
1602			return NULL;
1603		}
1604
1605		(void) hcksum_assoc(m, NULL, NULL, start, stuff, end,
1606		    value, flags, 0);
1607
1608		m->b_prev = m2;
1609		m->b_rptr += inc;
1610		fin->fin_m = m;
1611		ip = MTOD(m, char *) + ipoff;
1612		qpi->qpi_data = ip;
1613	}
1614
1615	ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]);
1616	fin->fin_ip = (ip_t *)ip;
1617	if (fin->fin_dp != NULL)
1618		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1619
1620	if (len == fin->fin_plen)
1621		fin->fin_flx |= FI_COALESCE;
1622	return ip;
1623}
1624
1625
1626/*
1627 * Function:	fr_verifysrc
1628 * Returns:	int (really boolean)
1629 * Parameters:	fin - packet information
1630 *
1631 * Check whether the packet has a valid source address for the interface on
1632 * which the packet arrived, implementing the "fr_chksrc" feature.
1633 * Returns true iff the packet's source address is valid.
1634 */
1635int fr_verifysrc(fin)
1636fr_info_t *fin;
1637{
1638	net_handle_t net_data_p;
1639	phy_if_t phy_ifdata_routeto;
1640	struct sockaddr	sin;
1641	ipf_stack_t *ifs = fin->fin_ifs;
1642
1643	if (fin->fin_v == 4) {
1644		net_data_p = ifs->ifs_ipf_ipv4;
1645	} else if (fin->fin_v == 6) {
1646		net_data_p = ifs->ifs_ipf_ipv6;
1647	} else {
1648		return (0);
1649	}
1650
1651	/* Get the index corresponding to the if name */
1652	sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
1653	bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr));
1654	phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL);
1655
1656	return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0);
1657}
1658
1659
1660/*
1661 * Function:	fr_fastroute
1662 * Returns:	 0: success;
1663 *		-1: failed
1664 * Parameters:
1665 *	mb: the message block where ip head starts
1666 *	mpp: the pointer to the pointer of the orignal
1667 *		packet message
1668 *	fin: packet information
1669 *	fdp: destination interface information
1670 *	if it is NULL, no interface information provided.
1671 *
1672 * This function is for fastroute/to/dup-to rules. It calls
1673 * pfil_make_lay2_packet to search route, make lay-2 header
1674 * ,and identify output queue for the IP packet.
1675 * The destination address depends on the following conditions:
1676 * 1: for fastroute rule, fdp is passed in as NULL, so the
1677 *	destination address is the IP Packet's destination address
1678 * 2: for to/dup-to rule, if an ip address is specified after
1679 *	the interface name, this address is the as destination
1680 *	address. Otherwise IP Packet's destination address is used
1681 */
1682int fr_fastroute(mb, mpp, fin, fdp)
1683mblk_t *mb, **mpp;
1684fr_info_t *fin;
1685frdest_t *fdp;
1686{
1687        net_handle_t net_data_p;
1688	net_inject_t *inj;
1689	mblk_t *mp = NULL;
1690	frentry_t *fr = fin->fin_fr;
1691	qpktinfo_t *qpi;
1692	ip_t *ip;
1693
1694	struct sockaddr_in *sin;
1695	struct sockaddr_in6 *sin6;
1696	struct sockaddr *sinp;
1697	ipf_stack_t *ifs = fin->fin_ifs;
1698#ifndef	sparc
1699	u_short __iplen, __ipoff;
1700#endif
1701
1702	if (fin->fin_v == 4) {
1703		net_data_p = ifs->ifs_ipf_ipv4;
1704	} else if (fin->fin_v == 6) {
1705		net_data_p = ifs->ifs_ipf_ipv6;
1706	} else {
1707		return (-1);
1708	}
1709
1710	inj = net_inject_alloc(NETINFO_VERSION);
1711	if (inj == NULL)
1712		return -1;
1713
1714	ip = fin->fin_ip;
1715	qpi = fin->fin_qpi;
1716
1717	/*
1718	 * If this is a duplicate mblk then we want ip to point at that
1719	 * data, not the original, if and only if it is already pointing at
1720	 * the current mblk data.
1721	 *
1722	 * Otherwise, if it's not a duplicate, and we're not already pointing
1723	 * at the current mblk data, then we want to ensure that the data
1724	 * points at ip.
1725	 */
1726
1727	if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) {
1728		ip = (ip_t *)mb->b_rptr;
1729	} else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) {
1730		qpi->qpi_m->b_rptr = (uchar_t *)ip;
1731		qpi->qpi_off = 0;
1732	}
1733
1734	/*
1735	 * If there is another M_PROTO, we don't want it
1736	 */
1737	if (*mpp != mb) {
1738		mp = unlinkb(*mpp);
1739		freeb(*mpp);
1740		*mpp = mp;
1741	}
1742
1743	sinp = (struct sockaddr *)&inj->ni_addr;
1744	sin = (struct sockaddr_in *)sinp;
1745	sin6 = (struct sockaddr_in6 *)sinp;
1746	bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr));
1747	inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
1748	inj->ni_packet = mb;
1749
1750	/*
1751	 * In case we're here due to "to <if>" being used with
1752	 * "keep state", check that we're going in the correct
1753	 * direction.
1754	 */
1755	if (fdp != NULL) {
1756		if ((fr != NULL) && (fdp->fd_ifp != NULL) &&
1757			(fin->fin_rev != 0) && (fdp == &fr->fr_tif))
1758			goto bad_fastroute;
1759		inj->ni_physical = (phy_if_t)fdp->fd_ifp;
1760		if (fin->fin_v == 4) {
1761			sin->sin_addr = fdp->fd_ip;
1762		} else {
1763			sin6->sin6_addr = fdp->fd_ip6.in6;
1764		}
1765	} else {
1766		if (fin->fin_v == 4) {
1767			sin->sin_addr = ip->ip_dst;
1768		} else {
1769			sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst;
1770		}
1771		inj->ni_physical = net_routeto(net_data_p, sinp, NULL);
1772	}
1773
1774	/*
1775	 * Clear the hardware checksum flags from packets that we are doing
1776	 * input processing on as leaving them set will cause the outgoing
1777	 * NIC (if it supports hardware checksum) to calculate them anew,
1778	 * using the old (correct) checksums as the pseudo value to start
1779	 * from.
1780	 */
1781	if (fin->fin_out == 0) {
1782		DB_CKSUMFLAGS(mb) = 0;
1783	}
1784
1785	*mpp = mb;
1786
1787	if (fin->fin_out == 0) {
1788		void *saveifp;
1789		u_32_t pass;
1790
1791		saveifp = fin->fin_ifp;
1792		fin->fin_ifp = (void *)inj->ni_physical;
1793		fin->fin_flx &= ~FI_STATE;
1794		fin->fin_out = 1;
1795		(void) fr_acctpkt(fin, &pass);
1796		fin->fin_fr = NULL;
1797		if (!fr || !(fr->fr_flags & FR_RETMASK))
1798			(void) fr_checkstate(fin, &pass);
1799		if (fr_checknatout(fin, NULL) == -1)
1800			goto bad_fastroute;
1801		fin->fin_out = 0;
1802		fin->fin_ifp = saveifp;
1803
1804		if (fin->fin_nat != NULL)
1805			fr_natderef((nat_t **)&fin->fin_nat, ifs);
1806	}
1807#ifndef	sparc
1808	if (fin->fin_v == 4) {
1809		__iplen = (u_short)ip->ip_len,
1810		__ipoff = (u_short)ip->ip_off;
1811
1812		ip->ip_len = htons(__iplen);
1813		ip->ip_off = htons(__ipoff);
1814	}
1815#endif
1816
1817	if (net_data_p) {
1818		if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) {
1819			net_inject_free(inj);
1820			return (-1);
1821		}
1822	}
1823
1824	ifs->ifs_fr_frouteok[0]++;
1825	net_inject_free(inj);
1826	return 0;
1827bad_fastroute:
1828	net_inject_free(inj);
1829	freemsg(mb);
1830	ifs->ifs_fr_frouteok[1]++;
1831	return -1;
1832}
1833
1834
1835/* ------------------------------------------------------------------------ */
1836/* Function:    ipf_hook4_out                                               */
1837/* Returns:     int - 0 == packet ok, else problem, free packet if not done */
1838/* Parameters:  event(I)     - pointer to event                             */
1839/*              info(I)      - pointer to hook information for firewalling  */
1840/*                                                                          */
1841/* Calling ipf_hook.                                                        */
1842/* ------------------------------------------------------------------------ */
1843/*ARGSUSED*/
1844int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg)
1845{
1846	return ipf_hook(info, 1, 0, arg);
1847}
1848/*ARGSUSED*/
1849int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg)
1850{
1851	return ipf_hook6(info, 1, 0, arg);
1852}
1853
1854/* ------------------------------------------------------------------------ */
1855/* Function:    ipf_hook4_in                                                */
1856/* Returns:     int - 0 == packet ok, else problem, free packet if not done */
1857/* Parameters:  event(I)     - pointer to event                             */
1858/*              info(I)      - pointer to hook information for firewalling  */
1859/*                                                                          */
1860/* Calling ipf_hook.                                                        */
1861/* ------------------------------------------------------------------------ */
1862/*ARGSUSED*/
1863int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg)
1864{
1865	return ipf_hook(info, 0, 0, arg);
1866}
1867/*ARGSUSED*/
1868int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg)
1869{
1870	return ipf_hook6(info, 0, 0, arg);
1871}
1872
1873
1874/* ------------------------------------------------------------------------ */
1875/* Function:    ipf_hook4_loop_out                                          */
1876/* Returns:     int - 0 == packet ok, else problem, free packet if not done */
1877/* Parameters:  event(I)     - pointer to event                             */
1878/*              info(I)      - pointer to hook information for firewalling  */
1879/*                                                                          */
1880/* Calling ipf_hook.                                                        */
1881/* ------------------------------------------------------------------------ */
1882/*ARGSUSED*/
1883int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
1884{
1885	return ipf_hook(info, 1, FI_NOCKSUM, arg);
1886}
1887/*ARGSUSED*/
1888int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
1889{
1890	return ipf_hook6(info, 1, FI_NOCKSUM, arg);
1891}
1892
1893/* ------------------------------------------------------------------------ */
1894/* Function:    ipf_hook4_loop_in                                           */
1895/* Returns:     int - 0 == packet ok, else problem, free packet if not done */
1896/* Parameters:  event(I)     - pointer to event                             */
1897/*              info(I)      - pointer to hook information for firewalling  */
1898/*                                                                          */
1899/* Calling ipf_hook.                                                        */
1900/* ------------------------------------------------------------------------ */
1901/*ARGSUSED*/
1902int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
1903{
1904	return ipf_hook(info, 0, FI_NOCKSUM, arg);
1905}
1906/*ARGSUSED*/
1907int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
1908{
1909	return ipf_hook6(info, 0, FI_NOCKSUM, arg);
1910}
1911
1912/* ------------------------------------------------------------------------ */
1913/* Function:    ipf_hook                                                    */
1914/* Returns:     int - 0 == packet ok, else problem, free packet if not done */
1915/* Parameters:  info(I)      - pointer to hook information for firewalling  */
1916/*              out(I)       - whether packet is going in or out            */
1917/*              loopback(I)  - whether packet is a loopback packet or not   */
1918/*                                                                          */
1919/* Stepping stone function between the IP mainline and IPFilter.  Extracts  */
1920/* parameters out of the info structure and forms them up to be useful for  */
1921/* calling ipfilter.                                                        */
1922/* ------------------------------------------------------------------------ */
1923int ipf_hook(hook_data_t info, int out, int loopback, void *arg)
1924{
1925	hook_pkt_event_t *fw;
1926	ipf_stack_t *ifs;
1927	qpktinfo_t qpi;
1928	int rval, hlen;
1929	u_short swap;
1930	phy_if_t phy;
1931	ip_t *ip;
1932
1933	ifs = arg;
1934	fw = (hook_pkt_event_t *)info;
1935
1936	ASSERT(fw != NULL);
1937	phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
1938
1939	ip = fw->hpe_hdr;
1940	swap = ntohs(ip->ip_len);
1941	ip->ip_len = swap;
1942	swap = ntohs(ip->ip_off);
1943	ip->ip_off = swap;
1944	hlen = IPH_HDR_LENGTH(ip);
1945
1946	qpi.qpi_m = fw->hpe_mb;
1947	qpi.qpi_data = fw->hpe_hdr;
1948	qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
1949	qpi.qpi_ill = (void *)phy;
1950	qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
1951	if (qpi.qpi_flags)
1952		qpi.qpi_flags |= FI_MBCAST;
1953	qpi.qpi_flags |= loopback;
1954
1955	rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
1956	    &qpi, fw->hpe_mp, ifs);
1957
1958	/* For fastroute cases, fr_check returns 0 with mp set to NULL */
1959	if (rval == 0 && *(fw->hpe_mp) == NULL)
1960		rval = 1;
1961
1962	/* Notify IP the packet mblk_t and IP header pointers. */
1963	fw->hpe_mb = qpi.qpi_m;
1964	fw->hpe_hdr = qpi.qpi_data;
1965	if (rval == 0) {
1966		ip = qpi.qpi_data;
1967		swap = ntohs(ip->ip_len);
1968		ip->ip_len = swap;
1969		swap = ntohs(ip->ip_off);
1970		ip->ip_off = swap;
1971	}
1972	return rval;
1973
1974}
1975int ipf_hook6(hook_data_t info, int out, int loopback, void *arg)
1976{
1977	hook_pkt_event_t *fw;
1978	int rval, hlen;
1979	qpktinfo_t qpi;
1980	phy_if_t phy;
1981
1982	fw = (hook_pkt_event_t *)info;
1983
1984	ASSERT(fw != NULL);
1985	phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp;
1986
1987	hlen = sizeof (ip6_t);
1988
1989	qpi.qpi_m = fw->hpe_mb;
1990	qpi.qpi_data = fw->hpe_hdr;
1991	qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr;
1992	qpi.qpi_ill = (void *)phy;
1993	qpi.qpi_flags = fw->hpe_flags & (HPE_MULTICAST|HPE_BROADCAST);
1994	if (qpi.qpi_flags)
1995		qpi.qpi_flags |= FI_MBCAST;
1996	qpi.qpi_flags |= loopback;
1997
1998	rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
1999	    &qpi, fw->hpe_mp, arg);
2000
2001	/* For fastroute cases, fr_check returns 0 with mp set to NULL */
2002	if (rval == 0 && *(fw->hpe_mp) == NULL)
2003		rval = 1;
2004
2005	/* Notify IP the packet mblk_t and IP header pointers. */
2006	fw->hpe_mb = qpi.qpi_m;
2007	fw->hpe_hdr = qpi.qpi_data;
2008	return rval;
2009
2010}
2011
2012
2013/* ------------------------------------------------------------------------ */
2014/* Function:    ipf_nic_event_v4                                            */
2015/* Returns:     int - 0 == no problems encountered                          */
2016/* Parameters:  event(I)     - pointer to event                             */
2017/*              info(I)      - pointer to information about a NIC event     */
2018/*                                                                          */
2019/* Function to receive asynchronous NIC events from IP                      */
2020/* ------------------------------------------------------------------------ */
2021/*ARGSUSED*/
2022int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg)
2023{
2024	struct sockaddr_in *sin;
2025	hook_nic_event_t *hn;
2026	ipf_stack_t *ifs = arg;
2027
2028	hn = (hook_nic_event_t *)info;
2029
2030	switch (hn->hne_event)
2031	{
2032	case NE_PLUMB :
2033		frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data,
2034		       ifs);
2035		fr_natifpsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
2036			      hn->hne_data, ifs);
2037		fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic,
2038			     hn->hne_data, ifs);
2039		break;
2040
2041	case NE_UNPLUMB :
2042		frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
2043		fr_natifpsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL,
2044			      ifs);
2045		fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs);
2046		break;
2047
2048	case NE_ADDRESS_CHANGE :
2049		/*
2050		 * We only respond to events for logical interface 0 because
2051		 * IPFilter only uses the first address given to a network
2052		 * interface.  We check for hne_lif==1 because the netinfo
2053		 * code maps adds 1 to the lif number so that it can return
2054		 * 0 to indicate "no more lifs" when walking them.
2055		 */
2056		if (hn->hne_lif == 1) {
2057			frsync(IPFSYNC_RESYNC, 4, (void *)hn->hne_nic, NULL,
2058			    ifs);
2059			sin = hn->hne_data;
2060			fr_nataddrsync(4, (void *)hn->hne_nic, &sin->sin_addr,
2061			    ifs);
2062		}
2063		break;
2064
2065	default :
2066		break;
2067	}
2068
2069	return 0;
2070}
2071
2072
2073/* ------------------------------------------------------------------------ */
2074/* Function:    ipf_nic_event_v6                                            */
2075/* Returns:     int - 0 == no problems encountered                          */
2076/* Parameters:  event(I)     - pointer to event                             */
2077/*              info(I)      - pointer to information about a NIC event     */
2078/*                                                                          */
2079/* Function to receive asynchronous NIC events from IP                      */
2080/* ------------------------------------------------------------------------ */
2081/*ARGSUSED*/
2082int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg)
2083{
2084	struct sockaddr_in6 *sin6;
2085	hook_nic_event_t *hn;
2086	ipf_stack_t *ifs = arg;
2087
2088	hn = (hook_nic_event_t *)info;
2089
2090	switch (hn->hne_event)
2091	{
2092	case NE_PLUMB :
2093		frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2094		       hn->hne_data, ifs);
2095		fr_natifpsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2096			      hn->hne_data, ifs);
2097		fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic,
2098			     hn->hne_data, ifs);
2099		break;
2100
2101	case NE_UNPLUMB :
2102		frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
2103		fr_natifpsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL,
2104			      ifs);
2105		fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs);
2106		break;
2107
2108	case NE_ADDRESS_CHANGE :
2109		if (hn->hne_lif == 1) {
2110			sin6 = hn->hne_data;
2111			fr_nataddrsync(6, (void *)hn->hne_nic, &sin6->sin6_addr,
2112				       ifs);
2113		}
2114		break;
2115	default :
2116		break;
2117	}
2118
2119	return 0;
2120}
2121