xref: /onnv-gate/usr/src/uts/common/inet/ip/ip_netinfo.c (revision 4041:530c0817b983)
12958Sdr146992 /*
22958Sdr146992  * CDDL HEADER START
32958Sdr146992  *
42958Sdr146992  * The contents of this file are subject to the terms of the
52958Sdr146992  * Common Development and Distribution License (the "License").
62958Sdr146992  * You may not use this file except in compliance with the License.
72958Sdr146992  *
82958Sdr146992  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92958Sdr146992  * or http://www.opensolaris.org/os/licensing.
102958Sdr146992  * See the License for the specific language governing permissions
112958Sdr146992  * and limitations under the License.
122958Sdr146992  *
132958Sdr146992  * When distributing Covered Code, include this CDDL HEADER in each
142958Sdr146992  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152958Sdr146992  * If applicable, add the following below this CDDL HEADER, with the
162958Sdr146992  * fields enclosed by brackets "[]" replaced with your own identifying
172958Sdr146992  * information: Portions Copyright [yyyy] [name of copyright owner]
182958Sdr146992  *
192958Sdr146992  * CDDL HEADER END
202958Sdr146992  */
212958Sdr146992 /*
223448Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
232958Sdr146992  * Use is subject to license terms.
242958Sdr146992  */
252958Sdr146992 
262958Sdr146992 #pragma ident	"%Z%%M%	%I%	%E% SMI"
272958Sdr146992 
282958Sdr146992 #include <sys/param.h>
292958Sdr146992 #include <sys/types.h>
302958Sdr146992 #include <sys/systm.h>
312958Sdr146992 #include <sys/stream.h>
322958Sdr146992 #include <sys/strsubr.h>
332958Sdr146992 #include <sys/pattr.h>
342958Sdr146992 #include <sys/dlpi.h>
352958Sdr146992 #include <sys/atomic.h>
362958Sdr146992 #include <sys/sunddi.h>
372958Sdr146992 #include <sys/socket.h>
382958Sdr146992 #include <sys/neti.h>
392958Sdr146992 
402958Sdr146992 #include <netinet/in.h>
412958Sdr146992 #include <inet/common.h>
422958Sdr146992 #include <inet/mib2.h>
432958Sdr146992 #include <inet/ip.h>
442958Sdr146992 #include <inet/ip6.h>
452958Sdr146992 #include <inet/ip_if.h>
462958Sdr146992 #include <inet/ip_ire.h>
472958Sdr146992 #include <inet/ip_impl.h>
482958Sdr146992 #include <inet/ip_ndp.h>
492958Sdr146992 #include <inet/ipclassifier.h>
502958Sdr146992 #include <inet/ipp_common.h>
512958Sdr146992 #include <inet/ip_ftable.h>
522958Sdr146992 
532958Sdr146992 /*
542958Sdr146992  * IPv4 netinfo entry point declarations.
552958Sdr146992  */
563448Sdh155122 static int 		ip_getifname(phy_if_t, char *, const size_t,
573448Sdh155122     netstack_t *);
583448Sdh155122 static int 		ip_getmtu(phy_if_t, lif_if_t, netstack_t *);
593448Sdh155122 static int 		ip_getpmtuenabled(netstack_t *);
602958Sdr146992 static int 		ip_getlifaddr(phy_if_t, lif_if_t, size_t,
613448Sdh155122 			    net_ifaddr_t [], void *, netstack_t *);
623448Sdh155122 static phy_if_t		ip_phygetnext(phy_if_t, netstack_t *);
633448Sdh155122 static phy_if_t 	ip_phylookup(const char *, netstack_t *);
643448Sdh155122 static lif_if_t 	ip_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
653448Sdh155122 static int 		ip_inject(inject_t, net_inject_t *, netstack_t *);
663448Sdh155122 static phy_if_t 	ip_routeto(struct sockaddr *, netstack_t *);
672958Sdr146992 static int 		ip_ispartialchecksum(mblk_t *);
682958Sdr146992 static int 		ip_isvalidchecksum(mblk_t *);
692958Sdr146992 
703448Sdh155122 static int 		ipv6_getifname(phy_if_t, char *, const size_t,
713448Sdh155122     netstack_t *);
723448Sdh155122 static int 		ipv6_getmtu(phy_if_t, lif_if_t, netstack_t *);
732958Sdr146992 static int 		ipv6_getlifaddr(phy_if_t, lif_if_t, size_t,
743448Sdh155122 			    net_ifaddr_t [], void *, netstack_t *);
753448Sdh155122 static phy_if_t 	ipv6_phygetnext(phy_if_t, netstack_t *);
763448Sdh155122 static phy_if_t 	ipv6_phylookup(const char *, netstack_t *);
773448Sdh155122 static lif_if_t 	ipv6_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
783448Sdh155122 static int 		ipv6_inject(inject_t, net_inject_t *, netstack_t *);
793448Sdh155122 static phy_if_t 	ipv6_routeto(struct sockaddr *, netstack_t *);
802958Sdr146992 static int 		ipv6_isvalidchecksum(mblk_t *);
812958Sdr146992 
822958Sdr146992 /* Netinfo private functions */
832958Sdr146992 static	int		ip_getifname_impl(phy_if_t, char *,
843448Sdh155122     const size_t, boolean_t, ip_stack_t *);
853448Sdh155122 static	int		ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t,
863448Sdh155122     ip_stack_t *);
873448Sdh155122 static	phy_if_t	ip_phylookup_impl(const char *, boolean_t,
883448Sdh155122     ip_stack_t *ipst);
893448Sdh155122 static	lif_if_t	ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t,
903448Sdh155122     ip_stack_t *ipst);
913448Sdh155122 static	int		ip_inject_impl(inject_t, net_inject_t *, boolean_t,
923448Sdh155122     ip_stack_t *);
932958Sdr146992 static	int		ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t,
942958Sdr146992 			    void *);
953448Sdh155122 static	phy_if_t	ip_routeto_impl(struct sockaddr *, ip_stack_t *);
962958Sdr146992 static	int		ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t,
973448Sdh155122 			    size_t, net_ifaddr_t [], struct sockaddr *,
983448Sdh155122 			    ip_stack_t *);
992958Sdr146992 static	void		ip_ni_queue_in_func(void *);
1002958Sdr146992 static	void		ip_ni_queue_out_func(void *);
1012958Sdr146992 static	void		ip_ni_queue_func_impl(injection_t *,  boolean_t);
1022958Sdr146992 
1032958Sdr146992 
1042958Sdr146992 static net_info_t ipv4info = {
1052958Sdr146992 	NETINFO_VERSION,
1062958Sdr146992 	NHF_INET,
1072958Sdr146992 	ip_getifname,
1082958Sdr146992 	ip_getmtu,
1092958Sdr146992 	ip_getpmtuenabled,
1102958Sdr146992 	ip_getlifaddr,
1112958Sdr146992 	ip_phygetnext,
1122958Sdr146992 	ip_phylookup,
1132958Sdr146992 	ip_lifgetnext,
1142958Sdr146992 	ip_inject,
1152958Sdr146992 	ip_routeto,
1162958Sdr146992 	ip_ispartialchecksum,
1172958Sdr146992 	ip_isvalidchecksum
1182958Sdr146992 };
1192958Sdr146992 
1202958Sdr146992 
1212958Sdr146992 static net_info_t ipv6info = {
1222958Sdr146992 	NETINFO_VERSION,
1232958Sdr146992 	NHF_INET6,
1242958Sdr146992 	ipv6_getifname,
1252958Sdr146992 	ipv6_getmtu,
1262958Sdr146992 	ip_getpmtuenabled,
1272958Sdr146992 	ipv6_getlifaddr,
1282958Sdr146992 	ipv6_phygetnext,
1292958Sdr146992 	ipv6_phylookup,
1302958Sdr146992 	ipv6_lifgetnext,
1312958Sdr146992 	ipv6_inject,
1322958Sdr146992 	ipv6_routeto,
1332958Sdr146992 	ip_ispartialchecksum,
1342958Sdr146992 	ipv6_isvalidchecksum
1352958Sdr146992 };
1362958Sdr146992 
1372958Sdr146992 /*
1382958Sdr146992  * The taskq eventq_queue_in is used to process the upside inject messages.
1392958Sdr146992  * The taskq eventq_queue_out is used to process the downside inject messages.
1402958Sdr146992  * The taskq eventq_queue_nic is used to process the nic event messages.
1412958Sdr146992  */
1422958Sdr146992 static ddi_taskq_t 	*eventq_queue_in = NULL;
1432958Sdr146992 static ddi_taskq_t 	*eventq_queue_out = NULL;
1442958Sdr146992 ddi_taskq_t 	*eventq_queue_nic = NULL;
1452958Sdr146992 
1462958Sdr146992 /*
1473448Sdh155122  * Initialize queues for inject.
1482958Sdr146992  */
1492958Sdr146992 void
1503448Sdh155122 ip_net_g_init()
1512958Sdr146992 {
1522958Sdr146992 	if (eventq_queue_out == NULL) {
1532958Sdr146992 		eventq_queue_out = ddi_taskq_create(NULL,
1542958Sdr146992 		    "IP_INJECT_QUEUE_OUT", 1, TASKQ_DEFAULTPRI, 0);
1552958Sdr146992 
1562958Sdr146992 		if (eventq_queue_out == NULL)
1572958Sdr146992 			cmn_err(CE_NOTE, "ipv4_net_init: "
1582958Sdr146992 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_OUT");
1592958Sdr146992 	}
1602958Sdr146992 
1612958Sdr146992 	if (eventq_queue_in == NULL) {
1622958Sdr146992 		eventq_queue_in = ddi_taskq_create(NULL,
1632958Sdr146992 		    "IP_INJECT_QUEUE_IN", 1, TASKQ_DEFAULTPRI, 0);
1642958Sdr146992 
1652958Sdr146992 		if (eventq_queue_in == NULL)
1662958Sdr146992 			cmn_err(CE_NOTE, "ipv4_net_init: "
1672958Sdr146992 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_IN");
1682958Sdr146992 	}
1692958Sdr146992 
1702958Sdr146992 	if (eventq_queue_nic == NULL) {
1712958Sdr146992 		eventq_queue_nic = ddi_taskq_create(NULL,
1722958Sdr146992 		    "IP_NIC_EVENT_QUEUE", 1, TASKQ_DEFAULTPRI, 0);
1732958Sdr146992 
1742958Sdr146992 		if (eventq_queue_nic == NULL)
1752958Sdr146992 			cmn_err(CE_NOTE, "ipv4_net_init: "
1762958Sdr146992 			    "ddi_taskq_create failed for IP_NIC_EVENT_QUEUE");
1772958Sdr146992 	}
1782958Sdr146992 }
1792958Sdr146992 
1802958Sdr146992 /*
1813448Sdh155122  * Destroy inject queues
1822958Sdr146992  */
1832958Sdr146992 void
1843448Sdh155122 ip_net_g_destroy()
1852958Sdr146992 {
1862958Sdr146992 	if (eventq_queue_nic != NULL) {
1872958Sdr146992 		ddi_taskq_destroy(eventq_queue_nic);
1882958Sdr146992 		eventq_queue_nic = NULL;
1892958Sdr146992 	}
1902958Sdr146992 
1912958Sdr146992 	if (eventq_queue_in != NULL) {
1922958Sdr146992 		ddi_taskq_destroy(eventq_queue_in);
1932958Sdr146992 		eventq_queue_in = NULL;
1942958Sdr146992 	}
1952958Sdr146992 
1962958Sdr146992 	if (eventq_queue_out != NULL) {
1972958Sdr146992 		ddi_taskq_destroy(eventq_queue_out);
1982958Sdr146992 		eventq_queue_out = NULL;
1992958Sdr146992 	}
2003448Sdh155122 }
2012958Sdr146992 
2023448Sdh155122 /*
2033448Sdh155122  * Register IPv4 and IPv6 netinfo functions and initialize queues for inject.
2043448Sdh155122  */
2053448Sdh155122 void
2063448Sdh155122 ip_net_init(ip_stack_t *ipst, netstack_t *ns)
2073448Sdh155122 {
2083448Sdh155122 
2093448Sdh155122 	ipst->ips_ipv4_net_data = net_register_impl(&ipv4info, ns);
2103448Sdh155122 	ASSERT(ipst->ips_ipv4_net_data != NULL);
2113448Sdh155122 
2123448Sdh155122 	ipst->ips_ipv6_net_data = net_register_impl(&ipv6info, ns);
2133448Sdh155122 	ASSERT(ipst->ips_ipv6_net_data != NULL);
2143448Sdh155122 }
2153448Sdh155122 
2163448Sdh155122 
2173448Sdh155122 /*
2183448Sdh155122  * Unregister IPv4 and IPv6 functions and inject queues
2193448Sdh155122  */
2203448Sdh155122 void
2213448Sdh155122 ip_net_destroy(ip_stack_t *ipst)
2223448Sdh155122 {
2233448Sdh155122 	if (ipst->ips_ipv4_net_data != NULL) {
2243448Sdh155122 		if (net_unregister(ipst->ips_ipv4_net_data) == 0)
2253448Sdh155122 			ipst->ips_ipv4_net_data = NULL;
2262958Sdr146992 	}
2272958Sdr146992 
2283448Sdh155122 	if (ipst->ips_ipv6_net_data != NULL) {
2293448Sdh155122 		if (net_unregister(ipst->ips_ipv6_net_data) == 0)
2303448Sdh155122 			ipst->ips_ipv6_net_data = NULL;
2312958Sdr146992 	}
2322958Sdr146992 }
2332958Sdr146992 
2342958Sdr146992 /*
2352958Sdr146992  * Initialize IPv4 hooks family the event
2362958Sdr146992  */
2372958Sdr146992 void
2383448Sdh155122 ipv4_hook_init(ip_stack_t *ipst)
2392958Sdr146992 {
2403448Sdh155122 	HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4);
2413448Sdh155122 	if (net_register_family(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root)
2423448Sdh155122 	    != 0) {
2432958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2442958Sdr146992 		    "net_register_family failed for ipv4");
2452958Sdr146992 	}
2462958Sdr146992 
2473448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN);
2483448Sdh155122 	ipst->ips_ipv4firewall_physical_in = net_register_event(
2493448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event);
2503448Sdh155122 	if (ipst->ips_ipv4firewall_physical_in == NULL) {
2512958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2522958Sdr146992 		    "net_register_event failed for ipv4/physical_in");
2532958Sdr146992 	}
2542958Sdr146992 
2553448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT);
2563448Sdh155122 	ipst->ips_ipv4firewall_physical_out = net_register_event(
2573448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event);
2583448Sdh155122 	if (ipst->ips_ipv4firewall_physical_out == NULL) {
2592958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2602958Sdr146992 		    "net_register_event failed for ipv4/physical_out");
2612958Sdr146992 	}
2622958Sdr146992 
2633448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING);
2643448Sdh155122 	ipst->ips_ipv4firewall_forwarding = net_register_event(
2653448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event);
2663448Sdh155122 	if (ipst->ips_ipv4firewall_forwarding == NULL) {
2672958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2682958Sdr146992 		    "net_register_event failed for ipv4/forwarding");
2692958Sdr146992 	}
2702958Sdr146992 
2713448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN);
2723448Sdh155122 	ipst->ips_ipv4firewall_loopback_in = net_register_event(
2733448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event);
2743448Sdh155122 	if (ipst->ips_ipv4firewall_loopback_in == NULL) {
2752958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2762958Sdr146992 		    "net_register_event failed for ipv4/loopback_in");
2772958Sdr146992 	}
2782958Sdr146992 
2793448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT);
2803448Sdh155122 	ipst->ips_ipv4firewall_loopback_out = net_register_event(
2813448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event);
2823448Sdh155122 	if (ipst->ips_ipv4firewall_loopback_out == NULL) {
2832958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2842958Sdr146992 		    "net_register_event failed for ipv4/loopback_out");
2852958Sdr146992 	}
2862958Sdr146992 
2873448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS);
2883448Sdh155122 	ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY;
2893448Sdh155122 	ipst->ips_ipv4nicevents = net_register_event(
2903448Sdh155122 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events);
2913448Sdh155122 	if (ipst->ips_ipv4nicevents == NULL) {
2922958Sdr146992 		cmn_err(CE_NOTE, "ipv4_hook_init: "
2932958Sdr146992 		    "net_register_event failed for ipv4/nic_events");
2942958Sdr146992 	}
2952958Sdr146992 }
2962958Sdr146992 
2972958Sdr146992 void
2983448Sdh155122 ipv4_hook_destroy(ip_stack_t *ipst)
2992958Sdr146992 {
3003448Sdh155122 	if (ipst->ips_ipv4firewall_forwarding != NULL) {
3013448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3023448Sdh155122 		    &ipst->ips_ip4_forwarding_event) == 0)
3033448Sdh155122 			ipst->ips_ipv4firewall_forwarding = NULL;
3042958Sdr146992 	}
3052958Sdr146992 
3063448Sdh155122 	if (ipst->ips_ipv4firewall_physical_in != NULL) {
3073448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3083448Sdh155122 		    &ipst->ips_ip4_physical_in_event) == 0)
3093448Sdh155122 			ipst->ips_ipv4firewall_physical_in = NULL;
3102958Sdr146992 	}
3112958Sdr146992 
3123448Sdh155122 	if (ipst->ips_ipv4firewall_physical_out != NULL) {
3133448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3143448Sdh155122 		    &ipst->ips_ip4_physical_out_event) == 0)
3153448Sdh155122 			ipst->ips_ipv4firewall_physical_out = NULL;
3162958Sdr146992 	}
3172958Sdr146992 
3183448Sdh155122 	if (ipst->ips_ipv4firewall_loopback_in != NULL) {
3193448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3203448Sdh155122 		    &ipst->ips_ip4_loopback_in_event) == 0)
3213448Sdh155122 			ipst->ips_ipv4firewall_loopback_in = NULL;
3222958Sdr146992 	}
3232958Sdr146992 
3243448Sdh155122 	if (ipst->ips_ipv4firewall_loopback_out != NULL) {
3253448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3263448Sdh155122 		    &ipst->ips_ip4_loopback_out_event) == 0)
3273448Sdh155122 			ipst->ips_ipv4firewall_loopback_out = NULL;
3282958Sdr146992 	}
3292958Sdr146992 
3303448Sdh155122 	if (ipst->ips_ipv4nicevents != NULL) {
3313448Sdh155122 		if (net_unregister_event(ipst->ips_ipv4_net_data,
3323448Sdh155122 		    &ipst->ips_ip4_nic_events) == 0)
3333448Sdh155122 			ipst->ips_ipv4nicevents = NULL;
3342958Sdr146992 	}
3352958Sdr146992 
3363448Sdh155122 	(void) net_unregister_family(ipst->ips_ipv4_net_data,
3373448Sdh155122 	    &ipst->ips_ipv4root);
3382958Sdr146992 }
3392958Sdr146992 
3402958Sdr146992 /*
3412958Sdr146992  * Initialize IPv6 hooks family and event
3422958Sdr146992  */
3432958Sdr146992 void
3443448Sdh155122 ipv6_hook_init(ip_stack_t *ipst)
3452958Sdr146992 {
3462958Sdr146992 
3473448Sdh155122 	HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6);
3483448Sdh155122 	if (net_register_family(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root)
3493448Sdh155122 	    != 0) {
3502958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3512958Sdr146992 		    "net_register_family failed for ipv6");
3522958Sdr146992 	}
3532958Sdr146992 
3543448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN);
3553448Sdh155122 	ipst->ips_ipv6firewall_physical_in = net_register_event(
3563448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event);
3573448Sdh155122 	if (ipst->ips_ipv6firewall_physical_in == NULL) {
3582958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3592958Sdr146992 		    "net_register_event failed for ipv6/physical_in");
3602958Sdr146992 	}
3612958Sdr146992 
3623448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT);
3633448Sdh155122 	ipst->ips_ipv6firewall_physical_out = net_register_event(
3643448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event);
3653448Sdh155122 	if (ipst->ips_ipv6firewall_physical_out == NULL) {
3662958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3672958Sdr146992 		    "net_register_event failed for ipv6/physical_out");
3682958Sdr146992 	}
3692958Sdr146992 
3703448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING);
3713448Sdh155122 	ipst->ips_ipv6firewall_forwarding = net_register_event(
3723448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event);
3733448Sdh155122 	if (ipst->ips_ipv6firewall_forwarding == NULL) {
3742958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3752958Sdr146992 		    "net_register_event failed for ipv6/forwarding");
3762958Sdr146992 	}
3772958Sdr146992 
3783448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN);
3793448Sdh155122 	ipst->ips_ipv6firewall_loopback_in = net_register_event(
3803448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event);
3813448Sdh155122 	if (ipst->ips_ipv6firewall_loopback_in == NULL) {
3822958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3832958Sdr146992 		    "net_register_event failed for ipv6/loopback_in");
3842958Sdr146992 	}
3852958Sdr146992 
3863448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT);
3873448Sdh155122 	ipst->ips_ipv6firewall_loopback_out = net_register_event(
3883448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event);
3893448Sdh155122 	if (ipst->ips_ipv6firewall_loopback_out == NULL) {
3902958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
3912958Sdr146992 		    "net_register_event failed for ipv6/loopback_out");
3922958Sdr146992 	}
3932958Sdr146992 
3943448Sdh155122 	HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS);
3953448Sdh155122 	ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY;
3963448Sdh155122 	ipst->ips_ipv6nicevents = net_register_event(
3973448Sdh155122 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events);
3983448Sdh155122 	if (ipst->ips_ipv6nicevents == NULL) {
3992958Sdr146992 		cmn_err(CE_NOTE, "ipv6_hook_init: "
4002958Sdr146992 		    "net_register_event failed for ipv6/nic_events");
4012958Sdr146992 	}
4022958Sdr146992 }
4032958Sdr146992 
4042958Sdr146992 void
4053448Sdh155122 ipv6_hook_destroy(ip_stack_t *ipst)
4062958Sdr146992 {
4073448Sdh155122 	if (ipst->ips_ipv6firewall_forwarding != NULL) {
4083448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4093448Sdh155122 		    &ipst->ips_ip6_forwarding_event) == 0)
4103448Sdh155122 			ipst->ips_ipv6firewall_forwarding = NULL;
4112958Sdr146992 	}
4122958Sdr146992 
4133448Sdh155122 	if (ipst->ips_ipv6firewall_physical_in != NULL) {
4143448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4153448Sdh155122 		    &ipst->ips_ip6_physical_in_event) == 0)
4163448Sdh155122 			ipst->ips_ipv6firewall_physical_in = NULL;
4172958Sdr146992 	}
4182958Sdr146992 
4193448Sdh155122 	if (ipst->ips_ipv6firewall_physical_out != NULL) {
4203448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4213448Sdh155122 		    &ipst->ips_ip6_physical_out_event) == 0)
4223448Sdh155122 			ipst->ips_ipv6firewall_physical_out = NULL;
4232958Sdr146992 	}
4242958Sdr146992 
4253448Sdh155122 	if (ipst->ips_ipv6firewall_loopback_in != NULL) {
4263448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4273448Sdh155122 		    &ipst->ips_ip6_loopback_in_event) == 0)
4283448Sdh155122 			ipst->ips_ipv6firewall_loopback_in = NULL;
4292958Sdr146992 	}
4302958Sdr146992 
4313448Sdh155122 	if (ipst->ips_ipv6firewall_loopback_out != NULL) {
4323448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4333448Sdh155122 		    &ipst->ips_ip6_loopback_out_event) == 0)
4343448Sdh155122 			ipst->ips_ipv6firewall_loopback_out = NULL;
4352958Sdr146992 	}
4362958Sdr146992 
4373448Sdh155122 	if (ipst->ips_ipv6nicevents != NULL) {
4383448Sdh155122 		if (net_unregister_event(ipst->ips_ipv6_net_data,
4393448Sdh155122 		    &ipst->ips_ip6_nic_events) == 0)
4403448Sdh155122 			ipst->ips_ipv6nicevents = NULL;
4412958Sdr146992 	}
4422958Sdr146992 
4433448Sdh155122 	(void) net_unregister_family(ipst->ips_ipv6_net_data,
4443448Sdh155122 	    &ipst->ips_ipv6root);
4452958Sdr146992 }
4462958Sdr146992 
4472958Sdr146992 /*
4482958Sdr146992  * Determine the name of an IPv4 interface
4492958Sdr146992  */
4502958Sdr146992 static int
4513448Sdh155122 ip_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
4523448Sdh155122     netstack_t *ns)
4532958Sdr146992 {
4543448Sdh155122 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE,
4553448Sdh155122 	    ns->netstack_ip));
4562958Sdr146992 }
4572958Sdr146992 
4582958Sdr146992 /*
4592958Sdr146992  * Determine the name of an IPv6 interface
4602958Sdr146992  */
4612958Sdr146992 static int
4623448Sdh155122 ipv6_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
4633448Sdh155122     netstack_t *ns)
4642958Sdr146992 {
4653448Sdh155122 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE,
4663448Sdh155122 	    ns->netstack_ip));
4672958Sdr146992 }
4682958Sdr146992 
4692958Sdr146992 /*
4702958Sdr146992  * Shared implementation to determine the name of a given network interface
4712958Sdr146992  */
4722958Sdr146992 /* ARGSUSED */
4732958Sdr146992 static int
4742958Sdr146992 ip_getifname_impl(phy_if_t phy_ifdata,
4753448Sdh155122     char *buffer, const size_t buflen, boolean_t isv6, ip_stack_t *ipst)
4762958Sdr146992 {
4772958Sdr146992 	ill_t *ill;
478*4041Snordmark 	char *name;
4792958Sdr146992 
4802958Sdr146992 	ASSERT(buffer != NULL);
4812958Sdr146992 
4822958Sdr146992 	ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, NULL, NULL,
4833448Sdh155122 	    NULL, NULL, ipst);
484*4041Snordmark 	if (ill != NULL) {
485*4041Snordmark 		name = ill->ill_name;
486*4041Snordmark 	} else {
487*4041Snordmark 		/* Fallback to group names only if hook_emulation is set */
488*4041Snordmark 		if (ipst->ips_ipmp_hook_emulation) {
489*4041Snordmark 			ill = ill_group_lookup_on_ifindex((uint_t)phy_ifdata,
490*4041Snordmark 			    isv6, ipst);
491*4041Snordmark 		}
492*4041Snordmark 		if (ill == NULL)
493*4041Snordmark 			return (1);
494*4041Snordmark 		name = ill->ill_phyint->phyint_groupname;
495*4041Snordmark 	}
496*4041Snordmark 	if (name != NULL) {
497*4041Snordmark 		(void) strlcpy(buffer, name, buflen);
4982958Sdr146992 		ill_refrele(ill);
4992958Sdr146992 		return (0);
5002958Sdr146992 	} else {
5012958Sdr146992 		ill_refrele(ill);
5022958Sdr146992 		return (1);
5032958Sdr146992 	}
5042958Sdr146992 
5052958Sdr146992 }
5062958Sdr146992 
5072958Sdr146992 /*
5082958Sdr146992  * Determine the MTU of an IPv4 network interface
5092958Sdr146992  */
5102958Sdr146992 static int
5113448Sdh155122 ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
5122958Sdr146992 {
5133448Sdh155122 	ASSERT(ns != NULL);
5143448Sdh155122 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip));
5152958Sdr146992 }
5162958Sdr146992 
5172958Sdr146992 /*
5182958Sdr146992  * Determine the MTU of an IPv6 network interface
5192958Sdr146992  */
5202958Sdr146992 static int
5213448Sdh155122 ipv6_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
5222958Sdr146992 {
5233448Sdh155122 	ASSERT(ns != NULL);
5243448Sdh155122 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip));
5252958Sdr146992 }
5262958Sdr146992 
5272958Sdr146992 /*
5282958Sdr146992  * Shared implementation to determine the MTU of a network interface
529*4041Snordmark  *
530*4041Snordmark  * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
531*4041Snordmark  * But IP Filter only uses a zero ifdata.
5322958Sdr146992  */
5332958Sdr146992 /* ARGSUSED */
5342958Sdr146992 static int
5353448Sdh155122 ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
5363448Sdh155122     ip_stack_t *ipst)
5372958Sdr146992 {
5382958Sdr146992 	lif_if_t ipifid;
5392958Sdr146992 	ipif_t *ipif;
5402958Sdr146992 	int mtu;
5412958Sdr146992 
5422958Sdr146992 	ipifid = UNMAP_IPIF_ID(ifdata);
5432958Sdr146992 
5443448Sdh155122 	ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid,
5453448Sdh155122 	    isv6, ipst);
5462958Sdr146992 	if (ipif == NULL)
5472958Sdr146992 		return (0);
5482958Sdr146992 
5492958Sdr146992 	mtu = ipif->ipif_mtu;
5502958Sdr146992 	ipif_refrele(ipif);
5512958Sdr146992 
5522958Sdr146992 	if (mtu == 0) {
5532958Sdr146992 		ill_t *ill;
5542958Sdr146992 
5552958Sdr146992 		if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6,
5563448Sdh155122 		    NULL, NULL, NULL, NULL, ipst)) == NULL) {
557*4041Snordmark 			/*
558*4041Snordmark 			 * Fallback to group names only if hook_emulation
559*4041Snordmark 			 * is set
560*4041Snordmark 			 */
561*4041Snordmark 			if (ipst->ips_ipmp_hook_emulation) {
562*4041Snordmark 				ill = ill_group_lookup_on_ifindex(
563*4041Snordmark 				    (uint_t)phy_ifdata, isv6, ipst);
564*4041Snordmark 			}
565*4041Snordmark 			if (ill == NULL)
566*4041Snordmark 				return (0);
5672958Sdr146992 		}
5682958Sdr146992 		mtu = ill->ill_max_frag;
5692958Sdr146992 		ill_refrele(ill);
5702958Sdr146992 	}
5712958Sdr146992 
5722958Sdr146992 	return (mtu);
5732958Sdr146992 }
5742958Sdr146992 
5752958Sdr146992 /*
5762958Sdr146992  * Determine if path MTU discovery is enabled for IP
5772958Sdr146992  */
5782958Sdr146992 static int
5793448Sdh155122 ip_getpmtuenabled(netstack_t *ns)
5802958Sdr146992 {
5813448Sdh155122 	ASSERT(ns != NULL);
5823448Sdh155122 	return ((ns->netstack_ip)->ips_ip_path_mtu_discovery);
5832958Sdr146992 }
5842958Sdr146992 
5852958Sdr146992 /*
5862958Sdr146992  * Get next interface from the current list of IPv4 physical network interfaces
587*4041Snordmark  *
588*4041Snordmark  * Note: this does not handle the case when ipmp_hook_emulation is set.
589*4041Snordmark  * But IP Filter does not use this function.
5902958Sdr146992  */
5912958Sdr146992 static phy_if_t
5923448Sdh155122 ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
5932958Sdr146992 {
5943448Sdh155122 	ASSERT(ns != NULL);
5953448Sdh155122 	return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip));
5962958Sdr146992 }
5972958Sdr146992 
5982958Sdr146992 /*
5992958Sdr146992  * Get next interface from the current list of IPv6 physical network interfaces
6002958Sdr146992  */
6012958Sdr146992 static phy_if_t
6023448Sdh155122 ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
6032958Sdr146992 {
6043448Sdh155122 	ASSERT(ns != NULL);
6053448Sdh155122 	return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip));
6062958Sdr146992 }
6072958Sdr146992 
6082958Sdr146992 /*
6092958Sdr146992  * Determine if a network interface name exists for IPv4
6102958Sdr146992  */
6112958Sdr146992 static phy_if_t
6123448Sdh155122 ip_phylookup(const char *name, netstack_t *ns)
6132958Sdr146992 {
6143448Sdh155122 	ASSERT(ns != NULL);
6153448Sdh155122 	return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip));
6162958Sdr146992 }
6172958Sdr146992 
6182958Sdr146992 /*
6192958Sdr146992  * Determine if a network interface name exists for IPv6
6202958Sdr146992  */
6212958Sdr146992 static phy_if_t
6223448Sdh155122 ipv6_phylookup(const char *name, netstack_t *ns)
6232958Sdr146992 {
6243448Sdh155122 	ASSERT(ns != NULL);
6253448Sdh155122 	return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip));
6262958Sdr146992 }
6272958Sdr146992 
6282958Sdr146992 /*
6292958Sdr146992  * Implement looking up an ill_t based on the name supplied and matching
6302958Sdr146992  * it up with either IPv4 or IPv6.  ill_get_ifindex_by_name() is not used
6312958Sdr146992  * because it does not match on the address family in addition to the name.
6322958Sdr146992  */
6332958Sdr146992 static phy_if_t
6343448Sdh155122 ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst)
6352958Sdr146992 {
6362958Sdr146992 	phy_if_t phy;
6372958Sdr146992 	ill_t *ill;
6382958Sdr146992 
6392958Sdr146992 	ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, NULL,
6403448Sdh155122 	    NULL, NULL, NULL, ipst);
6412958Sdr146992 
642*4041Snordmark 	/* Fallback to group names only if hook_emulation is set */
643*4041Snordmark 	if (ill == NULL && ipst->ips_ipmp_hook_emulation) {
644*4041Snordmark 		ill = ill_group_lookup_on_name((char *)name, isv6, ipst);
645*4041Snordmark 	}
6462958Sdr146992 	if (ill == NULL)
6472958Sdr146992 		return (0);
6482958Sdr146992 
649*4041Snordmark 	phy = ill->ill_phyint->phyint_hook_ifindex;
6502958Sdr146992 
6512958Sdr146992 	ill_refrele(ill);
6522958Sdr146992 
6532958Sdr146992 	return (phy);
6542958Sdr146992 }
6552958Sdr146992 
6562958Sdr146992 /*
6572958Sdr146992  * Get next interface from the current list of IPv4 logical network interfaces
6582958Sdr146992  */
6592958Sdr146992 static lif_if_t
6603448Sdh155122 ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
6612958Sdr146992 {
6623448Sdh155122 	ASSERT(ns != NULL);
6633448Sdh155122 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE,
6643448Sdh155122 	    ns->netstack_ip));
6652958Sdr146992 }
6662958Sdr146992 
6672958Sdr146992 /*
6682958Sdr146992  * Get next interface from the current list of IPv6 logical network interfaces
6692958Sdr146992  */
6702958Sdr146992 static lif_if_t
6713448Sdh155122 ipv6_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
6722958Sdr146992 {
6733448Sdh155122 	ASSERT(ns != NULL);
6743448Sdh155122 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE,
6753448Sdh155122 	    ns->netstack_ip));
6762958Sdr146992 }
6772958Sdr146992 
6782958Sdr146992 /*
6792958Sdr146992  * Shared implementation to get next interface from the current list of
6802958Sdr146992  * logical network interfaces
681*4041Snordmark  *
682*4041Snordmark  * Note: this does not handle the case when ipmp_hook_emulation is set.
683*4041Snordmark  * But IP Filter does not use this function.
6842958Sdr146992  */
6852958Sdr146992 static lif_if_t
6863448Sdh155122 ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
6873448Sdh155122     ip_stack_t *ipst)
6882958Sdr146992 {
6892958Sdr146992 	lif_if_t newidx, oldidx;
6902958Sdr146992 	boolean_t nextok;
6912958Sdr146992 	ipif_t *ipif;
6922958Sdr146992 	ill_t *ill;
6932958Sdr146992 
6943448Sdh155122 	ill = ill_lookup_on_ifindex(phy_ifdata, isv6, NULL, NULL,
6953448Sdh155122 	    NULL, NULL, ipst);
6962958Sdr146992 	if (ill == NULL)
6972958Sdr146992 		return (0);
6982958Sdr146992 
6992958Sdr146992 	if (ifdata != 0) {
7002958Sdr146992 		oldidx = UNMAP_IPIF_ID(ifdata);
7012958Sdr146992 		nextok = B_FALSE;
7022958Sdr146992 	} else {
7032958Sdr146992 		oldidx = 0;
7042958Sdr146992 		nextok = B_TRUE;
7052958Sdr146992 	}
7062958Sdr146992 
7072958Sdr146992 	mutex_enter(&ill->ill_lock);
7082958Sdr146992 	if (ill->ill_state_flags & ILL_CONDEMNED) {
7092958Sdr146992 		mutex_exit(&ill->ill_lock);
7102958Sdr146992 		ill_refrele(ill);
7112958Sdr146992 		return (0);
7122958Sdr146992 	}
7132958Sdr146992 
7142958Sdr146992 	/*
7152958Sdr146992 	 * It's safe to iterate the ill_ipif list when holding an ill_lock.
7162958Sdr146992 	 * And it's also safe to access ipif_id without ipif refhold.
7172958Sdr146992 	 * See ipif_get_id().
7182958Sdr146992 	 */
7192958Sdr146992 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
7202958Sdr146992 		if (!IPIF_CAN_LOOKUP(ipif))
7212958Sdr146992 			continue;
7222958Sdr146992 		if (nextok) {
7232958Sdr146992 			ipif_refhold_locked(ipif);
7242958Sdr146992 			break;
7252958Sdr146992 		} else if (oldidx == ipif->ipif_id) {
7262958Sdr146992 			nextok = B_TRUE;
7272958Sdr146992 		}
7282958Sdr146992 	}
7292958Sdr146992 
7302958Sdr146992 	mutex_exit(&ill->ill_lock);
7312958Sdr146992 	ill_refrele(ill);
7322958Sdr146992 
7332958Sdr146992 	if (ipif == NULL)
7342958Sdr146992 		return (0);
7352958Sdr146992 
7362958Sdr146992 	newidx = ipif->ipif_id;
7372958Sdr146992 	ipif_refrele(ipif);
7382958Sdr146992 
7392958Sdr146992 	return (MAP_IPIF_ID(newidx));
7402958Sdr146992 }
7412958Sdr146992 
7422958Sdr146992 /*
7432958Sdr146992  * Inject an IPv4 packet to or from an interface
7442958Sdr146992  */
7452958Sdr146992 static int
7463448Sdh155122 ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns)
7472958Sdr146992 {
7483448Sdh155122 	ASSERT(ns != NULL);
7493448Sdh155122 	return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip));
7502958Sdr146992 }
7512958Sdr146992 
7522958Sdr146992 
7532958Sdr146992 /*
7542958Sdr146992  * Inject an IPv6 packet to or from an interface
7552958Sdr146992  */
7562958Sdr146992 static int
7573448Sdh155122 ipv6_inject(inject_t style, net_inject_t *packet, netstack_t *ns)
7582958Sdr146992 {
7593448Sdh155122 	ASSERT(ns != NULL);
7603448Sdh155122 	return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip));
7612958Sdr146992 }
7622958Sdr146992 
7632958Sdr146992 /*
7642958Sdr146992  * Shared implementation to inject a packet to or from an interface
7652958Sdr146992  * Return value:
7662958Sdr146992  *   0: successful
7672958Sdr146992  *  -1: memory allocation failed
7682958Sdr146992  *   1: other errors
7692958Sdr146992  */
7702958Sdr146992 static int
7713448Sdh155122 ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6,
7723448Sdh155122     ip_stack_t *ipst)
7732958Sdr146992 {
7742958Sdr146992 	struct sockaddr_in6 *sin6;
7752958Sdr146992 	ddi_taskq_t *tq = NULL;
7763448Sdh155122 	void (* func)(void *);
7772958Sdr146992 	injection_t *inject;
7782958Sdr146992 	ip6_t *ip6h;
7792958Sdr146992 	ire_t *ire;
7802958Sdr146992 	mblk_t *mp;
7812958Sdr146992 
7822958Sdr146992 	ASSERT(packet != NULL);
7832958Sdr146992 	ASSERT(packet->ni_packet != NULL);
7842958Sdr146992 	ASSERT(packet->ni_packet->b_datap->db_type == M_DATA);
7852958Sdr146992 
7862958Sdr146992 	switch (style) {
7872958Sdr146992 	case NI_QUEUE_IN:
7882958Sdr146992 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
7892958Sdr146992 		if (inject == NULL)
7902958Sdr146992 			return (-1);
7912958Sdr146992 		inject->inj_data = *packet;
7922958Sdr146992 		inject->inj_isv6 = isv6;
7932958Sdr146992 		/*
7942958Sdr146992 		 * deliver up into the kernel, immitating its reception by a
7952958Sdr146992 		 * network interface, add to list and schedule timeout
7962958Sdr146992 		 */
7972958Sdr146992 		func = ip_ni_queue_in_func;
7982958Sdr146992 		tq = eventq_queue_in;
7992958Sdr146992 		break;
8002958Sdr146992 
8012958Sdr146992 	case NI_QUEUE_OUT:
8022958Sdr146992 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
8032958Sdr146992 		if (inject == NULL)
8042958Sdr146992 			return (-1);
8052958Sdr146992 		inject->inj_data = *packet;
8062958Sdr146992 		inject->inj_isv6 = isv6;
8072958Sdr146992 		/*
8082958Sdr146992 		 * deliver out of the kernel, as if it were being sent via a
8092958Sdr146992 		 * raw socket so that IPFilter will see it again, add to list
8102958Sdr146992 		 * and schedule timeout
8112958Sdr146992 		 */
8122958Sdr146992 		func = ip_ni_queue_out_func;
8132958Sdr146992 		tq = eventq_queue_out;
8142958Sdr146992 		break;
8152958Sdr146992 
8162958Sdr146992 	case NI_DIRECT_OUT:
8172958Sdr146992 		/*
8182958Sdr146992 		 * Note:
8192958Sdr146992 		 * For IPv4, the code path below will be greatly simplified
8202958Sdr146992 		 * with the delivery of surya - it will become a single
8212958Sdr146992 		 * function call to X.  A follow on project is aimed to
8222958Sdr146992 		 * provide similar functionality for IPv6.
8232958Sdr146992 		 */
8242958Sdr146992 		mp = packet->ni_packet;
8252958Sdr146992 
8262958Sdr146992 		if (!isv6) {
8272958Sdr146992 			struct sockaddr *sock;
8282958Sdr146992 
8292958Sdr146992 			sock = (struct sockaddr *)&packet->ni_addr;
8302958Sdr146992 			/*
8312958Sdr146992 			 * ipfil_sendpkt was provided by surya to ease the
8322958Sdr146992 			 * problems associated with sending out a packet.
8332958Sdr146992 			 * Currently this function only supports IPv4.
8342958Sdr146992 			 */
8352958Sdr146992 			switch (ipfil_sendpkt(sock, mp, packet->ni_physical,
8363448Sdh155122 			    netstackid_to_zoneid(
8373448Sdh155122 			    ipst->ips_netstack->netstack_stackid))) {
8382958Sdr146992 			case 0 :
8392958Sdr146992 			case EINPROGRESS:
8402958Sdr146992 				return (0);
8412958Sdr146992 			case ECOMM :
8422958Sdr146992 			case ENONET :
8432958Sdr146992 				return (1);
8442958Sdr146992 			default :
8452958Sdr146992 				return (1);
8462958Sdr146992 			}
8472958Sdr146992 			/* NOTREACHED */
8482958Sdr146992 
8492958Sdr146992 		}
8502958Sdr146992 
8512958Sdr146992 		ip6h = (ip6_t *)mp->b_rptr;
8522958Sdr146992 		sin6 = (struct sockaddr_in6 *)&packet->ni_addr;
8532958Sdr146992 		ASSERT(sin6->sin6_family == AF_INET6);
8542958Sdr146992 
8552958Sdr146992 		ire = ire_route_lookup_v6(&sin6->sin6_addr, 0, 0, 0,
8562958Sdr146992 		    NULL, NULL, ALL_ZONES, NULL,
8573448Sdh155122 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
8583448Sdh155122 		    ipst);
8592958Sdr146992 
8602958Sdr146992 		if (ire == NULL) {
8612958Sdr146992 			ip2dbg(("ip_inject: ire_cache_lookup failed\n"));
8622958Sdr146992 			freemsg(mp);
8632958Sdr146992 			return (1);
8642958Sdr146992 		}
8652958Sdr146992 
8662958Sdr146992 		if (ire->ire_stq == NULL) {
8672958Sdr146992 			/* Send to loopback destination. */
8682958Sdr146992 			if (ire->ire_rfq == NULL) {
8692958Sdr146992 				ip2dbg(("ip_inject: bad nexthop\n"));
8702958Sdr146992 				ire_refrele(ire);
8712958Sdr146992 				freemsg(mp);
8722958Sdr146992 				return (1);
8732958Sdr146992 			}
8742958Sdr146992 			ip_wput_local_v6(ire->ire_rfq,
8752958Sdr146992 			    ire->ire_ipif->ipif_ill, ip6h, mp, ire, 0);
8762958Sdr146992 			ire_refrele(ire);
8772958Sdr146992 			return (0);
8782958Sdr146992 		}
8792958Sdr146992 
8802958Sdr146992 		mp->b_queue = ire->ire_stq;
8812958Sdr146992 
8822958Sdr146992 		if (ire->ire_nce == NULL ||
8832958Sdr146992 		    ire->ire_nce->nce_fp_mp == NULL &&
8842958Sdr146992 		    ire->ire_nce->nce_res_mp == NULL) {
8852958Sdr146992 			ip_newroute_v6(ire->ire_stq, mp,
8863448Sdh155122 			    &sin6->sin6_addr, NULL, NULL, ALL_ZONES, ipst);
8872958Sdr146992 
8882958Sdr146992 			ire_refrele(ire);
8892958Sdr146992 			return (0);
8902958Sdr146992 		} else {
8912958Sdr146992 			/* prepend L2 header for IPv6 packets. */
8922958Sdr146992 			mblk_t *llmp;
8932958Sdr146992 
8942958Sdr146992 			/*
8952958Sdr146992 			 * Lock IREs, see 6420438
8962958Sdr146992 			 */
8972958Sdr146992 			mutex_enter(&ire->ire_lock);
8982958Sdr146992 			llmp = ire->ire_nce->nce_fp_mp ?
8992958Sdr146992 			    ire->ire_nce->nce_fp_mp :
9002958Sdr146992 			    ire->ire_nce->nce_res_mp;
9012958Sdr146992 
9022958Sdr146992 			if ((mp = dupb(llmp)) == NULL &&
9032958Sdr146992 			    (mp = copyb(llmp)) == NULL) {
9042958Sdr146992 				ip2dbg(("ip_inject: llhdr failed\n"));
9052958Sdr146992 				mutex_exit(&ire->ire_lock);
9062958Sdr146992 				ire_refrele(ire);
9072958Sdr146992 				freemsg(mp);
9082958Sdr146992 				return (1);
9092958Sdr146992 			}
9102958Sdr146992 			mutex_exit(&ire->ire_lock);
9112958Sdr146992 			linkb(mp, packet->ni_packet);
9122958Sdr146992 		}
9132958Sdr146992 
9142958Sdr146992 		mp->b_queue = ire->ire_stq;
9152958Sdr146992 
9162958Sdr146992 		break;
9172958Sdr146992 	default:
9182958Sdr146992 		freemsg(packet->ni_packet);
9192958Sdr146992 		return (1);
9202958Sdr146992 	}
9212958Sdr146992 
9222958Sdr146992 	if (tq) {
9233448Sdh155122 		inject->inj_ptr = ipst;
9242958Sdr146992 		if (ddi_taskq_dispatch(tq, func, (void *)inject,
9252958Sdr146992 		    DDI_SLEEP) == DDI_FAILURE) {
9262958Sdr146992 			ip2dbg(("ip_inject:  ddi_taskq_dispatch failed\n"));
9272958Sdr146992 			freemsg(packet->ni_packet);
9282958Sdr146992 			return (1);
9292958Sdr146992 		}
9302958Sdr146992 	} else {
9312958Sdr146992 		putnext(ire->ire_stq, mp);
9322958Sdr146992 		ire_refrele(ire);
9332958Sdr146992 	}
9342958Sdr146992 
9352958Sdr146992 	return (0);
9362958Sdr146992 }
9372958Sdr146992 
9382958Sdr146992 /*
9392958Sdr146992  * Find the interface used for traffic to a given IPv4 address
9402958Sdr146992  */
9412958Sdr146992 static phy_if_t
9423448Sdh155122 ip_routeto(struct sockaddr *address, netstack_t *ns)
9432958Sdr146992 {
9442958Sdr146992 	ASSERT(address != NULL);
9453448Sdh155122 	ASSERT(ns != NULL);
9462958Sdr146992 
9472958Sdr146992 	if (address->sa_family != AF_INET)
9482958Sdr146992 		return (0);
9493448Sdh155122 	return (ip_routeto_impl(address, ns->netstack_ip));
9502958Sdr146992 }
9512958Sdr146992 
9522958Sdr146992 /*
9532958Sdr146992  * Find the interface used for traffic to a given IPv6 address
9542958Sdr146992  */
9552958Sdr146992 static phy_if_t
9563448Sdh155122 ipv6_routeto(struct sockaddr *address, netstack_t *ns)
9572958Sdr146992 {
9582958Sdr146992 	ASSERT(address != NULL);
9593448Sdh155122 	ASSERT(ns != NULL);
9602958Sdr146992 
9612958Sdr146992 	if (address->sa_family != AF_INET6)
9622958Sdr146992 		return (0);
9633448Sdh155122 	return (ip_routeto_impl(address, ns->netstack_ip));
9642958Sdr146992 }
9652958Sdr146992 
9662958Sdr146992 
9672958Sdr146992 /*
9682958Sdr146992  * Find the interface used for traffic to an address
9692958Sdr146992  */
9702958Sdr146992 static phy_if_t
9713448Sdh155122 ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst)
9722958Sdr146992 {
9732958Sdr146992 	ire_t *ire;
9742958Sdr146992 	ill_t *ill;
9752958Sdr146992 	phy_if_t phy_if;
9762958Sdr146992 
9772958Sdr146992 	if (address->sa_family == AF_INET6) {
9782958Sdr146992 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address;
9792958Sdr146992 		ire = ire_route_lookup_v6(&sin6->sin6_addr, NULL,
9802958Sdr146992 		    0, 0, NULL, NULL, ALL_ZONES, NULL,
9813448Sdh155122 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
9823448Sdh155122 		    ipst);
9832958Sdr146992 	} else {
9842958Sdr146992 		struct sockaddr_in *sin = (struct sockaddr_in *)address;
9852958Sdr146992 		ire = ire_route_lookup(sin->sin_addr.s_addr, 0,
9862958Sdr146992 		    0, 0, NULL, NULL, ALL_ZONES, NULL,
9873448Sdh155122 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
9883448Sdh155122 		    ipst);
9892958Sdr146992 	}
9902958Sdr146992 
9912958Sdr146992 	if (ire == NULL)
9922958Sdr146992 		return (0);
9932958Sdr146992 
9942958Sdr146992 	ill = ire_to_ill(ire);
995*4041Snordmark 	if (ill == NULL) {
996*4041Snordmark 		ire_refrele(ire);
9972958Sdr146992 		return (0);
998*4041Snordmark 	}
9992958Sdr146992 
10002958Sdr146992 	ASSERT(ill != NULL);
1001*4041Snordmark 	phy_if = (phy_if_t)ill->ill_phyint->phyint_hook_ifindex;
10022958Sdr146992 	ire_refrele(ire);
10032958Sdr146992 
10042958Sdr146992 	return (phy_if);
10052958Sdr146992 }
10062958Sdr146992 
10072958Sdr146992 /*
10082958Sdr146992  * Determine if checksumming is being used for the given packet.
10092958Sdr146992  *
10102958Sdr146992  * Return value:
10112958Sdr146992  *   NET_HCK_NONE: full checksum recalculation is required
10122958Sdr146992  *   NET_HCK_L3_FULL: full layer 3 checksum
10132958Sdr146992  *   NET_HCK_L4_FULL: full layer 4 checksum
10142958Sdr146992  *   NET_HCK_L4_PART: partial layer 4 checksum
10152958Sdr146992  */
10162958Sdr146992 static int
10172958Sdr146992 ip_ispartialchecksum(mblk_t *mp)
10182958Sdr146992 {
10192958Sdr146992 	int ret = 0;
10202958Sdr146992 
10212958Sdr146992 	ASSERT(mp != NULL);
10222958Sdr146992 
10232958Sdr146992 	if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) {
10242958Sdr146992 		ret |= (int)NET_HCK_L4_FULL;
10252958Sdr146992 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
10262958Sdr146992 			ret |= (int)NET_HCK_L3_FULL;
10272958Sdr146992 	}
10282958Sdr146992 	if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) {
10292958Sdr146992 		ret |= (int)NET_HCK_L4_PART;
10302958Sdr146992 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
10312958Sdr146992 			ret |= (int)NET_HCK_L3_FULL;
10322958Sdr146992 	}
10332958Sdr146992 
10342958Sdr146992 	return (ret);
10352958Sdr146992 }
10362958Sdr146992 
10372958Sdr146992 /*
10382958Sdr146992  * Return true or false, indicating whether the network and transport
10392958Sdr146992  * headers are correct.  Use the capabilities flags and flags set in the
10402958Sdr146992  * dblk_t to determine whether or not the checksum is valid.
10412958Sdr146992  *
10422958Sdr146992  * Return:
10432958Sdr146992  *   0: the checksum was incorrect
10442958Sdr146992  *   1: the original checksum was correct
10452958Sdr146992  */
10462958Sdr146992 static int
10472958Sdr146992 ip_isvalidchecksum(mblk_t *mp)
10482958Sdr146992 {
10492958Sdr146992 	unsigned char *wptr;
10502958Sdr146992 	ipha_t *ipha = (ipha_t *)mp->b_rptr;
10512958Sdr146992 	int hlen;
10522958Sdr146992 	int ret;
10532958Sdr146992 
10542958Sdr146992 	ASSERT(mp != NULL);
10552958Sdr146992 
10562958Sdr146992 	if (dohwcksum &&
10572958Sdr146992 	    DB_CKSUM16(mp) != 0xFFFF &&
10582958Sdr146992 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) &&
10592958Sdr146992 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK) &&
10602958Sdr146992 	    (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM))
10612958Sdr146992 		return (1);
10622958Sdr146992 
10632958Sdr146992 	hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2;
10642958Sdr146992 
10652958Sdr146992 	/*
10662958Sdr146992 	 * Check that the mblk being passed in has enough data in it
10672958Sdr146992 	 * before blindly checking ip_cksum.
10682958Sdr146992 	 */
10692958Sdr146992 	if (msgdsize(mp) < hlen)
10702958Sdr146992 		return (0);
10712958Sdr146992 
10722958Sdr146992 	if (mp->b_wptr < mp->b_rptr + hlen) {
10732958Sdr146992 		if (pullupmsg(mp, hlen) == 0)
10742958Sdr146992 			return (0);
10752958Sdr146992 		wptr = mp->b_wptr;
10762958Sdr146992 	} else {
10772958Sdr146992 		wptr = mp->b_wptr;
10782958Sdr146992 		mp->b_wptr = mp->b_rptr + hlen;
10792958Sdr146992 	}
10802958Sdr146992 
10812958Sdr146992 	if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum))
10822958Sdr146992 		ret = 1;
10832958Sdr146992 	else
10842958Sdr146992 		ret = 0;
10852958Sdr146992 	mp->b_wptr = wptr;
10862958Sdr146992 
10872958Sdr146992 	return (ret);
10882958Sdr146992 }
10892958Sdr146992 
10902958Sdr146992 /*
10912958Sdr146992  * Unsupported with IPv6
10922958Sdr146992  */
10932958Sdr146992 /*ARGSUSED*/
10942958Sdr146992 static int
10952958Sdr146992 ipv6_isvalidchecksum(mblk_t *mp)
10962958Sdr146992 {
10972958Sdr146992 	return (-1);
10982958Sdr146992 }
10992958Sdr146992 
11002958Sdr146992 /*
11012958Sdr146992  * Determine the network addresses for an IPv4 interface
11022958Sdr146992  */
11032958Sdr146992 static int
11042958Sdr146992 ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
11053448Sdh155122 	net_ifaddr_t type[], void *storage, netstack_t *ns)
11062958Sdr146992 {
11073448Sdh155122 	ASSERT(ns != NULL);
11082958Sdr146992 	return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata,
11093448Sdh155122 	    nelem, type, storage, ns->netstack_ip));
11102958Sdr146992 }
11112958Sdr146992 
11122958Sdr146992 /*
11132958Sdr146992  * Determine the network addresses for an IPv6 interface
11142958Sdr146992  */
11152958Sdr146992 static int
11162958Sdr146992 ipv6_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
11173448Sdh155122 		net_ifaddr_t type[], void *storage, netstack_t *ns)
11182958Sdr146992 {
11193448Sdh155122 	ASSERT(ns != NULL);
11202958Sdr146992 	return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata,
11213448Sdh155122 	    nelem, type, storage, ns->netstack_ip));
11222958Sdr146992 }
11232958Sdr146992 
11242958Sdr146992 /*
11252958Sdr146992  * Shared implementation to determine the network addresses for an interface
1126*4041Snordmark  *
1127*4041Snordmark  * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
1128*4041Snordmark  * But IP Filter only uses a zero ifdata.
11292958Sdr146992  */
11302958Sdr146992 /* ARGSUSED */
11312958Sdr146992 static int
11322958Sdr146992 ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata,
11332958Sdr146992     lif_if_t ifdata, size_t nelem, net_ifaddr_t type[],
11343448Sdh155122     struct sockaddr *storage, ip_stack_t *ipst)
11352958Sdr146992 {
11362958Sdr146992 	struct sockaddr_in6 *sin6;
11372958Sdr146992 	struct sockaddr_in *sin;
11382958Sdr146992 	lif_if_t ipifid;
11392958Sdr146992 	ipif_t *ipif;
11402958Sdr146992 	int i;
11412958Sdr146992 
11422958Sdr146992 	ASSERT(type != NULL);
11432958Sdr146992 	ASSERT(storage != NULL);
11442958Sdr146992 
11452958Sdr146992 	ipifid = UNMAP_IPIF_ID(ifdata);
11462958Sdr146992 
11472958Sdr146992 	if (family == AF_INET) {
11482958Sdr146992 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
11493448Sdh155122 		    (uint_t)ipifid, B_FALSE, ipst)) == NULL)
11502958Sdr146992 			return (1);
11512958Sdr146992 
11522958Sdr146992 		sin = (struct sockaddr_in *)storage;
11532958Sdr146992 		for (i = 0; i < nelem; i++, sin++) {
11542958Sdr146992 			if (ip_getifaddr_type(AF_INET, ipif, type[i],
11552958Sdr146992 			    &sin->sin_addr) < 0) {
11562958Sdr146992 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
11572958Sdr146992 				    type[i]));
11582958Sdr146992 				ipif_refrele(ipif);
11592958Sdr146992 				return (1);
11602958Sdr146992 			}
11612958Sdr146992 		}
11622958Sdr146992 	} else {
11632958Sdr146992 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
11643448Sdh155122 		    (uint_t)ipifid, B_TRUE, ipst)) == NULL)
11652958Sdr146992 			return (1);
11662958Sdr146992 
11672958Sdr146992 		sin6 = (struct sockaddr_in6 *)storage;
11682958Sdr146992 		for (i = 0; i < nelem; i++, sin6++) {
11692958Sdr146992 			if (ip_getifaddr_type(AF_INET6, ipif, type[i],
11702958Sdr146992 			    &sin6->sin6_addr) < 0) {
11712958Sdr146992 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
11722958Sdr146992 				    type[i]));
11732958Sdr146992 				ipif_refrele(ipif);
11742958Sdr146992 				return (1);
11752958Sdr146992 			}
11762958Sdr146992 		}
11772958Sdr146992 	}
11782958Sdr146992 	ipif_refrele(ipif);
11792958Sdr146992 	return (0);
11802958Sdr146992 }
11812958Sdr146992 
11822958Sdr146992 /*
11832958Sdr146992  * ip_getlifaddr private function
11842958Sdr146992  */
11852958Sdr146992 static int
11862958Sdr146992 ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif,
11872958Sdr146992     lif_if_t type, void *storage)
11882958Sdr146992 {
11892958Sdr146992 	void *src_addr;
11902958Sdr146992 	int mem_size;
11912958Sdr146992 
11922958Sdr146992 	ASSERT(ill_ipif != NULL);
11932958Sdr146992 	ASSERT(storage != NULL);
11942958Sdr146992 
11952958Sdr146992 	if (family == AF_INET) {
11962958Sdr146992 		mem_size = sizeof (struct in_addr);
11972958Sdr146992 
11982958Sdr146992 		switch (type) {
11992958Sdr146992 		case NA_ADDRESS:
12002958Sdr146992 			src_addr = &(ill_ipif->ipif_lcl_addr);
12012958Sdr146992 			break;
12022958Sdr146992 		case NA_PEER:
12032958Sdr146992 			src_addr = &(ill_ipif->ipif_pp_dst_addr);
12042958Sdr146992 			break;
12052958Sdr146992 		case NA_BROADCAST:
12062958Sdr146992 			src_addr = &(ill_ipif->ipif_brd_addr);
12072958Sdr146992 			break;
12082958Sdr146992 		case NA_NETMASK:
12092958Sdr146992 			src_addr = &(ill_ipif->ipif_net_mask);
12102958Sdr146992 			break;
12112958Sdr146992 		default:
12122958Sdr146992 			return (-1);
12132958Sdr146992 			/*NOTREACHED*/
12142958Sdr146992 		}
12152958Sdr146992 	} else {
12162958Sdr146992 		mem_size = sizeof (struct in6_addr);
12172958Sdr146992 
12182958Sdr146992 		switch (type) {
12192958Sdr146992 		case NA_ADDRESS:
12202958Sdr146992 			src_addr = &(ill_ipif->ipif_v6lcl_addr);
12212958Sdr146992 			break;
12222958Sdr146992 		case NA_PEER:
12232958Sdr146992 			src_addr = &(ill_ipif->ipif_v6pp_dst_addr);
12242958Sdr146992 			break;
12252958Sdr146992 		case NA_BROADCAST:
12262958Sdr146992 			src_addr = &(ill_ipif->ipif_v6brd_addr);
12272958Sdr146992 			break;
12282958Sdr146992 		case NA_NETMASK:
12292958Sdr146992 			src_addr = &(ill_ipif->ipif_v6net_mask);
12302958Sdr146992 			break;
12312958Sdr146992 		default:
12322958Sdr146992 			return (-1);
12332958Sdr146992 			/*NOTREACHED*/
12342958Sdr146992 		}
12352958Sdr146992 	}
12362958Sdr146992 
12372958Sdr146992 	(void) memcpy(storage, src_addr, mem_size);
12382958Sdr146992 	return (1);
12392958Sdr146992 }
12402958Sdr146992 
12412958Sdr146992 /*
12422958Sdr146992  * Deliver packet up into the kernel, immitating its reception by a
12432958Sdr146992  * network interface.
12442958Sdr146992  */
12452958Sdr146992 static void
12462958Sdr146992 ip_ni_queue_in_func(void *inject)
12472958Sdr146992 {
12482958Sdr146992 	ip_ni_queue_func_impl(inject, B_FALSE);
12492958Sdr146992 }
12502958Sdr146992 
12512958Sdr146992 /*
12522958Sdr146992  * Deliver out of the kernel, as if it were being sent via a
12532958Sdr146992  * raw socket so that IPFilter will see it again.
12542958Sdr146992  */
12552958Sdr146992 static void
12562958Sdr146992 ip_ni_queue_out_func(void *inject)
12572958Sdr146992 {
12582958Sdr146992 	ip_ni_queue_func_impl(inject, B_TRUE);
12592958Sdr146992 }
12602958Sdr146992 
12612958Sdr146992 /*
12622958Sdr146992  * Shared implementation for inject via ip_output and ip_input
12632958Sdr146992  */
12642958Sdr146992 static void
12652958Sdr146992 ip_ni_queue_func_impl(injection_t *inject,  boolean_t out)
12662958Sdr146992 {
12672958Sdr146992 	net_inject_t *packet;
12682958Sdr146992 	conn_t *conn;
12692958Sdr146992 	ill_t *ill;
12703448Sdh155122 	ip_stack_t *ipst = (ip_stack_t *)inject->inj_ptr;
12712958Sdr146992 
12722958Sdr146992 	ASSERT(inject != NULL);
12732958Sdr146992 	packet = &inject->inj_data;
12742958Sdr146992 	ASSERT(packet->ni_packet != NULL);
12752958Sdr146992 
1276*4041Snordmark 	ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical,
1277*4041Snordmark 	    B_FALSE, NULL, NULL, NULL, NULL, ipst);
1278*4041Snordmark 
1279*4041Snordmark 	/* Fallback to group names only if hook_emulation is set */
1280*4041Snordmark 	if (ill == NULL && ipst->ips_ipmp_hook_emulation) {
1281*4041Snordmark 		ill = ill_group_lookup_on_ifindex((uint_t)packet->ni_physical,
1282*4041Snordmark 		    B_FALSE, ipst);
1283*4041Snordmark 	}
1284*4041Snordmark 	if (ill == NULL) {
12852958Sdr146992 		kmem_free(inject, sizeof (*inject));
12862958Sdr146992 		return;
12872958Sdr146992 	}
12882958Sdr146992 
12892958Sdr146992 	if (out == 0) {
12902958Sdr146992 		if (inject->inj_isv6) {
12912958Sdr146992 			ip_rput_v6(ill->ill_rq, packet->ni_packet);
12922958Sdr146992 		} else {
12932958Sdr146992 			ip_input(ill, NULL, packet->ni_packet, 0);
12942958Sdr146992 		}
12952958Sdr146992 		kmem_free(inject, sizeof (*inject));
12962958Sdr146992 		ill_refrele(ill);
12972958Sdr146992 		return;
12982958Sdr146992 	}
12992958Sdr146992 
13002958Sdr146992 	/*
13012958Sdr146992 	 * Even though ipcl_conn_create requests that it be passed
13022958Sdr146992 	 * a different value for "TCP", in this case there may not
13032958Sdr146992 	 * be a TCP connection backing the packet and more than
13042958Sdr146992 	 * likely, non-TCP packets will go here too.
13052958Sdr146992 	 */
13063448Sdh155122 	conn = ipcl_conn_create(IPCL_IPCCONN, KM_NOSLEEP, ipst->ips_netstack);
13072958Sdr146992 	if (conn != NULL) {
13082958Sdr146992 		if (inject->inj_isv6) {
13092958Sdr146992 			conn->conn_flags |= IPCL_ISV6;
13102958Sdr146992 			conn->conn_af_isv6 = B_TRUE;
13112958Sdr146992 			conn->conn_src_preferences = IPV6_PREFER_SRC_DEFAULT;
13122958Sdr146992 			conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
13132958Sdr146992 			ip_output_v6(conn, packet->ni_packet, ill->ill_wq,
13142958Sdr146992 				IP_WPUT);
13152958Sdr146992 		} else {
13162958Sdr146992 			conn->conn_af_isv6 = B_FALSE;
13172958Sdr146992 			conn->conn_pkt_isv6 = B_FALSE;
13182958Sdr146992 			conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
13192958Sdr146992 			ip_output(conn, packet->ni_packet, ill->ill_wq,
13202958Sdr146992 				IP_WPUT);
13212958Sdr146992 		}
13222958Sdr146992 
13232958Sdr146992 		CONN_DEC_REF(conn);
13242958Sdr146992 	}
13252958Sdr146992 
13262958Sdr146992 	kmem_free(inject, sizeof (*inject));
13272958Sdr146992 	ill_refrele(ill);
13282958Sdr146992 }
13292958Sdr146992 
13302958Sdr146992 /*
13312958Sdr146992  * taskq function for nic events.
13322958Sdr146992  */
13332958Sdr146992 void
13342958Sdr146992 ip_ne_queue_func(void *arg)
13352958Sdr146992 {
13362958Sdr146992 	hook_event_int_t *hr;
13372958Sdr146992 	hook_nic_event_t *info = (hook_nic_event_t *)arg;
13383448Sdh155122 	netstack_t *ns = info->hne_family->netd_netstack;
13393448Sdh155122 	ip_stack_t *ipst = ns->netstack_ip;
13402958Sdr146992 
13413448Sdh155122 	hr = (info->hne_family == ipst->ips_ipv6_net_data) ?
13423448Sdh155122 	    ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
13433448Sdh155122 	(void) hook_run(hr, (hook_data_t)info, ns);
13442958Sdr146992 
13452958Sdr146992 	if (info->hne_data != NULL)
13462958Sdr146992 		kmem_free(info->hne_data, info->hne_datalen);
13472958Sdr146992 	kmem_free(arg, sizeof (hook_nic_event_t));
13482958Sdr146992 }
1349*4041Snordmark 
1350*4041Snordmark /*
1351*4041Snordmark  * Temporary function to support IPMP emulation for IP Filter.
1352*4041Snordmark  * Lookup an ill based on the ifindex assigned to the group.
1353*4041Snordmark  * Skips unusable ones i.e. where any of these flags are set:
1354*4041Snordmark  * (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE)
1355*4041Snordmark  */
1356*4041Snordmark ill_t *
1357*4041Snordmark ill_group_lookup_on_ifindex(uint_t index, boolean_t isv6, ip_stack_t *ipst)
1358*4041Snordmark {
1359*4041Snordmark 	ill_t	*ill;
1360*4041Snordmark 	phyint_t *phyi;
1361*4041Snordmark 
1362*4041Snordmark 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
1363*4041Snordmark 	phyi = phyint_lookup_group_ifindex(index, ipst);
1364*4041Snordmark 	if (phyi != NULL) {
1365*4041Snordmark 		ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4;
1366*4041Snordmark 		if (ill != NULL) {
1367*4041Snordmark 			mutex_enter(&ill->ill_lock);
1368*4041Snordmark 			if (ILL_CAN_LOOKUP(ill)) {
1369*4041Snordmark 				ill_refhold_locked(ill);
1370*4041Snordmark 				mutex_exit(&ill->ill_lock);
1371*4041Snordmark 				rw_exit(&ipst->ips_ill_g_lock);
1372*4041Snordmark 				return (ill);
1373*4041Snordmark 			}
1374*4041Snordmark 		}
1375*4041Snordmark 	}
1376*4041Snordmark 	rw_exit(&ipst->ips_ill_g_lock);
1377*4041Snordmark 	return (NULL);
1378*4041Snordmark }
1379*4041Snordmark 
1380*4041Snordmark /*
1381*4041Snordmark  * Temporary function to support IPMP emulation for IP Filter.
1382*4041Snordmark  * Lookup an ill based on the group name.
1383*4041Snordmark  * Skips unusable ones i.e. where any of these flags are set:
1384*4041Snordmark  * (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE)
1385*4041Snordmark  */
1386*4041Snordmark ill_t *
1387*4041Snordmark ill_group_lookup_on_name(char *name, boolean_t isv6, ip_stack_t *ipst)
1388*4041Snordmark {
1389*4041Snordmark 	ill_t	*ill;
1390*4041Snordmark 	phyint_t *phyi;
1391*4041Snordmark 
1392*4041Snordmark 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
1393*4041Snordmark 	phyi = phyint_lookup_group(name, B_TRUE, ipst);
1394*4041Snordmark 	if (phyi != NULL) {
1395*4041Snordmark 		ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4;
1396*4041Snordmark 		if (ill != NULL) {
1397*4041Snordmark 			mutex_enter(&ill->ill_lock);
1398*4041Snordmark 			if (ILL_CAN_LOOKUP(ill)) {
1399*4041Snordmark 				ill_refhold_locked(ill);
1400*4041Snordmark 				mutex_exit(&ill->ill_lock);
1401*4041Snordmark 				rw_exit(&ipst->ips_ill_g_lock);
1402*4041Snordmark 				return (ill);
1403*4041Snordmark 			}
1404*4041Snordmark 		}
1405*4041Snordmark 	}
1406*4041Snordmark 	rw_exit(&ipst->ips_ill_g_lock);
1407*4041Snordmark 	return (NULL);
1408*4041Snordmark }
1409