Home | History | Annotate | Download | only in ip
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/param.h>
     27 #include <sys/types.h>
     28 #include <sys/systm.h>
     29 #include <sys/stream.h>
     30 #include <sys/strsubr.h>
     31 #include <sys/pattr.h>
     32 #include <sys/dlpi.h>
     33 #include <sys/atomic.h>
     34 #include <sys/sunddi.h>
     35 #include <sys/socket.h>
     36 #include <sys/neti.h>
     37 #include <sys/sdt.h>
     38 #include <sys/cmn_err.h>
     39 
     40 #include <netinet/in.h>
     41 #include <inet/ipsec_impl.h>
     42 #include <inet/common.h>
     43 #include <inet/mib2.h>
     44 #include <inet/ip.h>
     45 #include <inet/ip6.h>
     46 #include <inet/ip_if.h>
     47 #include <inet/ip_ire.h>
     48 #include <inet/ip_impl.h>
     49 #include <inet/ip_ndp.h>
     50 #include <inet/ipclassifier.h>
     51 #include <inet/ipp_common.h>
     52 #include <inet/ip_ftable.h>
     53 
     54 /*
     55  * IPv4 netinfo entry point declarations.
     56  */
     57 static int 		ip_getifname(net_handle_t, phy_if_t, char *,
     58 			    const size_t);
     59 static int 		ip_getmtu(net_handle_t, phy_if_t, lif_if_t);
     60 static int 		ip_getpmtuenabled(net_handle_t);
     61 static int 		ip_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
     62 			    size_t, net_ifaddr_t [], void *);
     63 static int		ip_getlifzone(net_handle_t, phy_if_t, lif_if_t,
     64 			    zoneid_t *);
     65 static int		ip_getlifflags(net_handle_t, phy_if_t, lif_if_t,
     66 			    uint64_t *);
     67 static phy_if_t		ip_phygetnext(net_handle_t, phy_if_t);
     68 static phy_if_t 	ip_phylookup(net_handle_t, const char *);
     69 static lif_if_t 	ip_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
     70 static int 		ip_inject(net_handle_t, inject_t, net_inject_t *);
     71 static phy_if_t 	ip_routeto(net_handle_t, struct sockaddr *,
     72 			    struct sockaddr *);
     73 static int 		ip_ispartialchecksum(net_handle_t, mblk_t *);
     74 static int 		ip_isvalidchecksum(net_handle_t, mblk_t *);
     75 
     76 static int 		ipv6_getifname(net_handle_t, phy_if_t, char *,
     77 			    const size_t);
     78 static int 		ipv6_getmtu(net_handle_t, phy_if_t, lif_if_t);
     79 static int 		ipv6_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
     80 			    size_t, net_ifaddr_t [], void *);
     81 static int		ipv6_getlifzone(net_handle_t, phy_if_t, lif_if_t,
     82 			    zoneid_t *);
     83 static int		ipv6_getlifflags(net_handle_t, phy_if_t, lif_if_t,
     84 			    uint64_t *);
     85 static phy_if_t 	ipv6_phygetnext(net_handle_t, phy_if_t);
     86 static phy_if_t 	ipv6_phylookup(net_handle_t, const char *);
     87 static lif_if_t 	ipv6_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
     88 static int 		ipv6_inject(net_handle_t, inject_t, net_inject_t *);
     89 static phy_if_t 	ipv6_routeto(net_handle_t, struct sockaddr *,
     90 			    struct sockaddr *);
     91 static int 		ipv6_isvalidchecksum(net_handle_t, mblk_t *);
     92 
     93 static int 		net_no_getmtu(net_handle_t, phy_if_t, lif_if_t);
     94 static int 		net_no_getpmtuenabled(net_handle_t);
     95 static lif_if_t 	net_no_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
     96 static int 		net_no_inject(net_handle_t, inject_t, net_inject_t *);
     97 static phy_if_t 	net_no_routeto(net_handle_t, struct sockaddr *,
     98 			    struct sockaddr *);
     99 static int 		net_no_ispartialchecksum(net_handle_t, mblk_t *);
    100 static int 		net_no_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
    101 			    size_t, net_ifaddr_t [], void *);
    102 static int		net_no_getlifzone(net_handle_t, phy_if_t, lif_if_t,
    103 			    zoneid_t *);
    104 static int		net_no_getlifflags(net_handle_t, phy_if_t, lif_if_t,
    105 			    uint64_t *);
    106 
    107 /* Netinfo private functions */
    108 static	int		ip_getifname_impl(phy_if_t, char *,
    109 			    const size_t, boolean_t, ip_stack_t *);
    110 static	int		ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t,
    111 			    ip_stack_t *);
    112 static	phy_if_t	ip_phylookup_impl(const char *, boolean_t,
    113 			    ip_stack_t *);
    114 static	lif_if_t	ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t,
    115 			    ip_stack_t *);
    116 static	int		ip_inject_impl(inject_t, net_inject_t *, boolean_t,
    117 			    ip_stack_t *);
    118 static	int		ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t,
    119 			    void *);
    120 static	phy_if_t	ip_routeto_impl(struct sockaddr *, struct sockaddr *,
    121 			    ip_stack_t *);
    122 static	int		ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t,
    123 			    size_t, net_ifaddr_t [], struct sockaddr *,
    124 			    ip_stack_t *);
    125 static	void		ip_ni_queue_in_func(void *);
    126 static	void		ip_ni_queue_out_func(void *);
    127 static	void		ip_ni_queue_func_impl(injection_t *,  boolean_t);
    128 
    129 static net_protocol_t ipv4info = {
    130 	NETINFO_VERSION,
    131 	NHF_INET,
    132 	ip_getifname,
    133 	ip_getmtu,
    134 	ip_getpmtuenabled,
    135 	ip_getlifaddr,
    136 	ip_getlifzone,
    137 	ip_getlifflags,
    138 	ip_phygetnext,
    139 	ip_phylookup,
    140 	ip_lifgetnext,
    141 	ip_inject,
    142 	ip_routeto,
    143 	ip_ispartialchecksum,
    144 	ip_isvalidchecksum
    145 };
    146 
    147 
    148 static net_protocol_t ipv6info = {
    149 	NETINFO_VERSION,
    150 	NHF_INET6,
    151 	ipv6_getifname,
    152 	ipv6_getmtu,
    153 	ip_getpmtuenabled,
    154 	ipv6_getlifaddr,
    155 	ipv6_getlifzone,
    156 	ipv6_getlifflags,
    157 	ipv6_phygetnext,
    158 	ipv6_phylookup,
    159 	ipv6_lifgetnext,
    160 	ipv6_inject,
    161 	ipv6_routeto,
    162 	ip_ispartialchecksum,
    163 	ipv6_isvalidchecksum
    164 };
    165 
    166 static net_protocol_t arp_netinfo = {
    167 	NETINFO_VERSION,
    168 	NHF_ARP,
    169 	ip_getifname,
    170 	net_no_getmtu,
    171 	net_no_getpmtuenabled,
    172 	net_no_getlifaddr,
    173 	net_no_getlifzone,
    174 	net_no_getlifflags,
    175 	ip_phygetnext,
    176 	ip_phylookup,
    177 	net_no_lifgetnext,
    178 	net_no_inject,
    179 	net_no_routeto,
    180 	net_no_ispartialchecksum,
    181 	ip_isvalidchecksum
    182 };
    183 
    184 /*
    185  * The taskq eventq_queue_in is used to process the upside inject messages.
    186  * The taskq eventq_queue_out is used to process the downside inject messages.
    187  * The taskq eventq_queue_nic is used to process the nic event messages.
    188  */
    189 static ddi_taskq_t 	*eventq_queue_in = NULL;
    190 static ddi_taskq_t 	*eventq_queue_out = NULL;
    191 ddi_taskq_t 	*eventq_queue_nic = NULL;
    192 
    193 /*
    194  * Initialize queues for inject.
    195  */
    196 void
    197 ip_net_g_init()
    198 {
    199 	if (eventq_queue_out == NULL) {
    200 		eventq_queue_out = ddi_taskq_create(NULL,
    201 		    "IP_INJECT_QUEUE_OUT", 1, TASKQ_DEFAULTPRI, 0);
    202 
    203 		if (eventq_queue_out == NULL)
    204 			cmn_err(CE_NOTE, "ipv4_net_init: "
    205 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_OUT");
    206 	}
    207 
    208 	if (eventq_queue_in == NULL) {
    209 		eventq_queue_in = ddi_taskq_create(NULL,
    210 		    "IP_INJECT_QUEUE_IN", 1, TASKQ_DEFAULTPRI, 0);
    211 
    212 		if (eventq_queue_in == NULL)
    213 			cmn_err(CE_NOTE, "ipv4_net_init: "
    214 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_IN");
    215 	}
    216 
    217 	if (eventq_queue_nic == NULL) {
    218 		eventq_queue_nic = ddi_taskq_create(NULL,
    219 		    "IP_NIC_EVENT_QUEUE", 1, TASKQ_DEFAULTPRI, 0);
    220 
    221 		if (eventq_queue_nic == NULL)
    222 			cmn_err(CE_NOTE, "ipv4_net_init: "
    223 			    "ddi_taskq_create failed for IP_NIC_EVENT_QUEUE");
    224 	}
    225 }
    226 
    227 /*
    228  * Destroy inject queues
    229  */
    230 void
    231 ip_net_g_destroy()
    232 {
    233 	if (eventq_queue_nic != NULL) {
    234 		ddi_taskq_destroy(eventq_queue_nic);
    235 		eventq_queue_nic = NULL;
    236 	}
    237 
    238 	if (eventq_queue_in != NULL) {
    239 		ddi_taskq_destroy(eventq_queue_in);
    240 		eventq_queue_in = NULL;
    241 	}
    242 
    243 	if (eventq_queue_out != NULL) {
    244 		ddi_taskq_destroy(eventq_queue_out);
    245 		eventq_queue_out = NULL;
    246 	}
    247 }
    248 
    249 /*
    250  * Register IPv4 and IPv6 netinfo functions and initialize queues for inject.
    251  */
    252 void
    253 ip_net_init(ip_stack_t *ipst, netstack_t *ns)
    254 {
    255 	netid_t id;
    256 
    257 	id = net_getnetidbynetstackid(ns->netstack_stackid);
    258 	ASSERT(id != -1);
    259 
    260 	ipst->ips_ipv4_net_data = net_protocol_register(id, &ipv4info);
    261 	ASSERT(ipst->ips_ipv4_net_data != NULL);
    262 
    263 	ipst->ips_ipv6_net_data = net_protocol_register(id, &ipv6info);
    264 	ASSERT(ipst->ips_ipv6_net_data != NULL);
    265 
    266 	ipst->ips_arp_net_data = net_protocol_register(id, &arp_netinfo);
    267 	ASSERT(ipst->ips_ipv6_net_data != NULL);
    268 }
    269 
    270 
    271 /*
    272  * Unregister IPv4 and IPv6 functions.
    273  */
    274 void
    275 ip_net_destroy(ip_stack_t *ipst)
    276 {
    277 	if (ipst->ips_ipv4_net_data != NULL) {
    278 		if (net_protocol_unregister(ipst->ips_ipv4_net_data) == 0)
    279 			ipst->ips_ipv4_net_data = NULL;
    280 	}
    281 
    282 	if (ipst->ips_ipv6_net_data != NULL) {
    283 		if (net_protocol_unregister(ipst->ips_ipv6_net_data) == 0)
    284 			ipst->ips_ipv6_net_data = NULL;
    285 	}
    286 
    287 	if (ipst->ips_arp_net_data != NULL) {
    288 		if (net_protocol_unregister(ipst->ips_arp_net_data) == 0)
    289 			ipst->ips_arp_net_data = NULL;
    290 	}
    291 }
    292 
    293 /*
    294  * Initialize IPv4 hooks family the event
    295  */
    296 void
    297 ipv4_hook_init(ip_stack_t *ipst)
    298 {
    299 	HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4);
    300 	if (net_family_register(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root)
    301 	    != 0) {
    302 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    303 		    "net_family_register failed for ipv4");
    304 	}
    305 
    306 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN);
    307 	ipst->ips_ipv4firewall_physical_in = net_event_register(
    308 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event);
    309 	if (ipst->ips_ipv4firewall_physical_in == NULL) {
    310 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    311 		    "net_event_register failed for ipv4/physical_in");
    312 	}
    313 
    314 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT);
    315 	ipst->ips_ipv4firewall_physical_out = net_event_register(
    316 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event);
    317 	if (ipst->ips_ipv4firewall_physical_out == NULL) {
    318 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    319 		    "net_event_register failed for ipv4/physical_out");
    320 	}
    321 
    322 	HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING);
    323 	ipst->ips_ipv4firewall_forwarding = net_event_register(
    324 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event);
    325 	if (ipst->ips_ipv4firewall_forwarding == NULL) {
    326 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    327 		    "net_event_register failed for ipv4/forwarding");
    328 	}
    329 
    330 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN);
    331 	ipst->ips_ipv4firewall_loopback_in = net_event_register(
    332 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event);
    333 	if (ipst->ips_ipv4firewall_loopback_in == NULL) {
    334 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    335 		    "net_event_register failed for ipv4/loopback_in");
    336 	}
    337 
    338 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT);
    339 	ipst->ips_ipv4firewall_loopback_out = net_event_register(
    340 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event);
    341 	if (ipst->ips_ipv4firewall_loopback_out == NULL) {
    342 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    343 		    "net_event_register failed for ipv4/loopback_out");
    344 	}
    345 
    346 	HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS);
    347 	ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY;
    348 	ipst->ips_ipv4nicevents = net_event_register(
    349 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events);
    350 	if (ipst->ips_ipv4nicevents == NULL) {
    351 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    352 		    "net_event_register failed for ipv4/nic_events");
    353 	}
    354 
    355 	HOOK_EVENT_INIT(&ipst->ips_ip4_observe, NH_OBSERVE);
    356 	ipst->ips_ip4_observe.he_flags = HOOK_RDONLY;
    357 	ipst->ips_ipv4observing = net_event_register(
    358 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_observe);
    359 	if (ipst->ips_ipv4observing == NULL) {
    360 		cmn_err(CE_NOTE, "ipv4_hook_init: "
    361 		    "net_event_register failed for ipv4/observe");
    362 	}
    363 
    364 }
    365 
    366 void
    367 ipv4_hook_shutdown(ip_stack_t *ipst)
    368 {
    369 	if (ipst->ips_ipv4firewall_forwarding != NULL) {
    370 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    371 		    &ipst->ips_ip4_forwarding_event);
    372 	}
    373 
    374 	if (ipst->ips_ipv4firewall_physical_in != NULL) {
    375 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    376 		    &ipst->ips_ip4_physical_in_event);
    377 	}
    378 
    379 	if (ipst->ips_ipv4firewall_physical_out != NULL) {
    380 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    381 		    &ipst->ips_ip4_physical_out_event);
    382 	}
    383 
    384 	if (ipst->ips_ipv4firewall_loopback_in != NULL) {
    385 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    386 		    &ipst->ips_ip4_loopback_in_event);
    387 	}
    388 
    389 	if (ipst->ips_ipv4firewall_loopback_out != NULL) {
    390 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    391 		    &ipst->ips_ip4_loopback_out_event);
    392 	}
    393 
    394 	if (ipst->ips_ipv4nicevents != NULL) {
    395 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    396 		    &ipst->ips_ip4_nic_events);
    397 	}
    398 
    399 	if (ipst->ips_ipv4observing != NULL) {
    400 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
    401 		    &ipst->ips_ip4_observe);
    402 	}
    403 
    404 	(void) net_family_shutdown(ipst->ips_ipv4_net_data,
    405 	    &ipst->ips_ipv4root);
    406 }
    407 
    408 void
    409 ipv4_hook_destroy(ip_stack_t *ipst)
    410 {
    411 	if (ipst->ips_ipv4firewall_forwarding != NULL) {
    412 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    413 		    &ipst->ips_ip4_forwarding_event) == 0)
    414 			ipst->ips_ipv4firewall_forwarding = NULL;
    415 	}
    416 
    417 	if (ipst->ips_ipv4firewall_physical_in != NULL) {
    418 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    419 		    &ipst->ips_ip4_physical_in_event) == 0)
    420 			ipst->ips_ipv4firewall_physical_in = NULL;
    421 	}
    422 
    423 	if (ipst->ips_ipv4firewall_physical_out != NULL) {
    424 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    425 		    &ipst->ips_ip4_physical_out_event) == 0)
    426 			ipst->ips_ipv4firewall_physical_out = NULL;
    427 	}
    428 
    429 	if (ipst->ips_ipv4firewall_loopback_in != NULL) {
    430 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    431 		    &ipst->ips_ip4_loopback_in_event) == 0)
    432 			ipst->ips_ipv4firewall_loopback_in = NULL;
    433 	}
    434 
    435 	if (ipst->ips_ipv4firewall_loopback_out != NULL) {
    436 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    437 		    &ipst->ips_ip4_loopback_out_event) == 0)
    438 			ipst->ips_ipv4firewall_loopback_out = NULL;
    439 	}
    440 
    441 	if (ipst->ips_ipv4nicevents != NULL) {
    442 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    443 		    &ipst->ips_ip4_nic_events) == 0)
    444 			ipst->ips_ipv4nicevents = NULL;
    445 	}
    446 
    447 	if (ipst->ips_ipv4observing != NULL) {
    448 		if (net_event_unregister(ipst->ips_ipv4_net_data,
    449 		    &ipst->ips_ip4_observe) == 0)
    450 			ipst->ips_ipv4observing = NULL;
    451 	}
    452 
    453 	(void) net_family_unregister(ipst->ips_ipv4_net_data,
    454 	    &ipst->ips_ipv4root);
    455 }
    456 
    457 /*
    458  * Initialize IPv6 hooks family and event
    459  */
    460 void
    461 ipv6_hook_init(ip_stack_t *ipst)
    462 {
    463 
    464 	HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6);
    465 	if (net_family_register(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root)
    466 	    != 0) {
    467 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    468 		    "net_family_register failed for ipv6");
    469 	}
    470 
    471 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN);
    472 	ipst->ips_ipv6firewall_physical_in = net_event_register(
    473 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event);
    474 	if (ipst->ips_ipv6firewall_physical_in == NULL) {
    475 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    476 		    "net_event_register failed for ipv6/physical_in");
    477 	}
    478 
    479 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT);
    480 	ipst->ips_ipv6firewall_physical_out = net_event_register(
    481 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event);
    482 	if (ipst->ips_ipv6firewall_physical_out == NULL) {
    483 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    484 		    "net_event_register failed for ipv6/physical_out");
    485 	}
    486 
    487 	HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING);
    488 	ipst->ips_ipv6firewall_forwarding = net_event_register(
    489 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event);
    490 	if (ipst->ips_ipv6firewall_forwarding == NULL) {
    491 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    492 		    "net_event_register failed for ipv6/forwarding");
    493 	}
    494 
    495 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN);
    496 	ipst->ips_ipv6firewall_loopback_in = net_event_register(
    497 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event);
    498 	if (ipst->ips_ipv6firewall_loopback_in == NULL) {
    499 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    500 		    "net_event_register failed for ipv6/loopback_in");
    501 	}
    502 
    503 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT);
    504 	ipst->ips_ipv6firewall_loopback_out = net_event_register(
    505 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event);
    506 	if (ipst->ips_ipv6firewall_loopback_out == NULL) {
    507 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    508 		    "net_event_register failed for ipv6/loopback_out");
    509 	}
    510 
    511 	HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS);
    512 	ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY;
    513 	ipst->ips_ipv6nicevents = net_event_register(
    514 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events);
    515 	if (ipst->ips_ipv6nicevents == NULL) {
    516 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    517 		    "net_event_register failed for ipv6/nic_events");
    518 	}
    519 
    520 	HOOK_EVENT_INIT(&ipst->ips_ip6_observe, NH_OBSERVE);
    521 	ipst->ips_ip6_observe.he_flags = HOOK_RDONLY;
    522 	ipst->ips_ipv6observing = net_event_register(
    523 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_observe);
    524 	if (ipst->ips_ipv6observing == NULL) {
    525 		cmn_err(CE_NOTE, "ipv6_hook_init: "
    526 		    "net_event_register failed for ipv6/observe");
    527 	}
    528 }
    529 
    530 void
    531 ipv6_hook_shutdown(ip_stack_t *ipst)
    532 {
    533 	if (ipst->ips_ipv6firewall_forwarding != NULL) {
    534 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    535 		    &ipst->ips_ip6_forwarding_event);
    536 	}
    537 
    538 	if (ipst->ips_ipv6firewall_physical_in != NULL) {
    539 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    540 		    &ipst->ips_ip6_physical_in_event);
    541 	}
    542 
    543 	if (ipst->ips_ipv6firewall_physical_out != NULL) {
    544 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    545 		    &ipst->ips_ip6_physical_out_event);
    546 	}
    547 
    548 	if (ipst->ips_ipv6firewall_loopback_in != NULL) {
    549 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    550 		    &ipst->ips_ip6_loopback_in_event);
    551 	}
    552 
    553 	if (ipst->ips_ipv6firewall_loopback_out != NULL) {
    554 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    555 		    &ipst->ips_ip6_loopback_out_event);
    556 	}
    557 
    558 	if (ipst->ips_ipv6nicevents != NULL) {
    559 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    560 		    &ipst->ips_ip6_nic_events);
    561 	}
    562 
    563 	if (ipst->ips_ipv6observing != NULL) {
    564 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
    565 		    &ipst->ips_ip6_observe);
    566 	}
    567 
    568 	(void) net_family_shutdown(ipst->ips_ipv6_net_data,
    569 	    &ipst->ips_ipv6root);
    570 }
    571 
    572 void
    573 ipv6_hook_destroy(ip_stack_t *ipst)
    574 {
    575 	if (ipst->ips_ipv6firewall_forwarding != NULL) {
    576 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    577 		    &ipst->ips_ip6_forwarding_event) == 0)
    578 			ipst->ips_ipv6firewall_forwarding = NULL;
    579 	}
    580 
    581 	if (ipst->ips_ipv6firewall_physical_in != NULL) {
    582 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    583 		    &ipst->ips_ip6_physical_in_event) == 0)
    584 			ipst->ips_ipv6firewall_physical_in = NULL;
    585 	}
    586 
    587 	if (ipst->ips_ipv6firewall_physical_out != NULL) {
    588 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    589 		    &ipst->ips_ip6_physical_out_event) == 0)
    590 			ipst->ips_ipv6firewall_physical_out = NULL;
    591 	}
    592 
    593 	if (ipst->ips_ipv6firewall_loopback_in != NULL) {
    594 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    595 		    &ipst->ips_ip6_loopback_in_event) == 0)
    596 			ipst->ips_ipv6firewall_loopback_in = NULL;
    597 	}
    598 
    599 	if (ipst->ips_ipv6firewall_loopback_out != NULL) {
    600 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    601 		    &ipst->ips_ip6_loopback_out_event) == 0)
    602 			ipst->ips_ipv6firewall_loopback_out = NULL;
    603 	}
    604 
    605 	if (ipst->ips_ipv6nicevents != NULL) {
    606 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    607 		    &ipst->ips_ip6_nic_events) == 0)
    608 			ipst->ips_ipv6nicevents = NULL;
    609 	}
    610 
    611 	if (ipst->ips_ipv6observing != NULL) {
    612 		if (net_event_unregister(ipst->ips_ipv6_net_data,
    613 		    &ipst->ips_ip6_observe) == 0)
    614 			ipst->ips_ipv6observing = NULL;
    615 	}
    616 
    617 	(void) net_family_unregister(ipst->ips_ipv6_net_data,
    618 	    &ipst->ips_ipv6root);
    619 }
    620 
    621 /*
    622  * Determine the name of an IPv4 interface
    623  */
    624 static int
    625 ip_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
    626     const size_t buflen)
    627 {
    628 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE,
    629 	    neti->netd_stack->nts_netstack->netstack_ip));
    630 }
    631 
    632 /*
    633  * Determine the name of an IPv6 interface
    634  */
    635 static int
    636 ipv6_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
    637     const size_t buflen)
    638 {
    639 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE,
    640 	    neti->netd_stack->nts_netstack->netstack_ip));
    641 }
    642 
    643 /*
    644  * Shared implementation to determine the name of a given network interface
    645  */
    646 /* ARGSUSED */
    647 static int
    648 ip_getifname_impl(phy_if_t phy_ifdata,
    649     char *buffer, const size_t buflen, boolean_t isv6, ip_stack_t *ipst)
    650 {
    651 	ill_t *ill;
    652 
    653 	ASSERT(buffer != NULL);
    654 
    655 	ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, ipst);
    656 	if (ill == NULL)
    657 		return (1);
    658 
    659 	(void) strlcpy(buffer, ill->ill_name, buflen);
    660 	ill_refrele(ill);
    661 	return (0);
    662 }
    663 
    664 /*
    665  * Determine the MTU of an IPv4 network interface
    666  */
    667 static int
    668 ip_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
    669 {
    670 	netstack_t *ns;
    671 
    672 	ns = neti->netd_stack->nts_netstack;
    673 	ASSERT(ns != NULL);
    674 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip));
    675 }
    676 
    677 /*
    678  * Determine the MTU of an IPv6 network interface
    679  */
    680 static int
    681 ipv6_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
    682 {
    683 	netstack_t *ns;
    684 
    685 	ns = neti->netd_stack->nts_netstack;
    686 	ASSERT(ns != NULL);
    687 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip));
    688 }
    689 
    690 /*
    691  * Shared implementation to determine the MTU of a network interface
    692  */
    693 /* ARGSUSED */
    694 static int
    695 ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
    696     ip_stack_t *ipst)
    697 {
    698 	lif_if_t ipifid;
    699 	ipif_t *ipif;
    700 	int mtu;
    701 
    702 	ipifid = UNMAP_IPIF_ID(ifdata);
    703 
    704 	ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid,
    705 	    isv6, ipst);
    706 	if (ipif == NULL)
    707 		return (0);
    708 
    709 	mtu = ipif->ipif_ill->ill_mtu;
    710 	ipif_refrele(ipif);
    711 
    712 	if (mtu == 0) {
    713 		ill_t *ill;
    714 
    715 		if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6,
    716 		    ipst)) == NULL) {
    717 			return (0);
    718 		}
    719 		mtu = ill->ill_mtu;
    720 		ill_refrele(ill);
    721 	}
    722 
    723 	return (mtu);
    724 }
    725 
    726 /*
    727  * Determine if path MTU discovery is enabled for IP
    728  */
    729 static int
    730 ip_getpmtuenabled(net_handle_t neti)
    731 {
    732 	netstack_t *ns;
    733 
    734 	ns = neti->netd_stack->nts_netstack;
    735 	ASSERT(ns != NULL);
    736 	return (ns->netstack_ip->ips_ip_path_mtu_discovery);
    737 }
    738 
    739 /*
    740  * Get next interface from the current list of IPv4 physical network interfaces
    741  */
    742 static phy_if_t
    743 ip_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
    744 {
    745 	netstack_t *ns;
    746 
    747 	ns = neti->netd_stack->nts_netstack;
    748 	ASSERT(ns != NULL);
    749 	return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip));
    750 }
    751 
    752 /*
    753  * Get next interface from the current list of IPv6 physical network interfaces
    754  */
    755 static phy_if_t
    756 ipv6_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
    757 {
    758 	netstack_t *ns;
    759 
    760 	ns = neti->netd_stack->nts_netstack;
    761 	ASSERT(ns != NULL);
    762 	return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip));
    763 }
    764 
    765 /*
    766  * Determine if a network interface name exists for IPv4
    767  */
    768 static phy_if_t
    769 ip_phylookup(net_handle_t neti, const char *name)
    770 {
    771 	netstack_t *ns;
    772 
    773 	ns = neti->netd_stack->nts_netstack;
    774 	ASSERT(ns != NULL);
    775 	return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip));
    776 }
    777 
    778 /*
    779  * Determine if a network interface name exists for IPv6
    780  */
    781 static phy_if_t
    782 ipv6_phylookup(net_handle_t neti, const char *name)
    783 {
    784 	netstack_t *ns;
    785 
    786 	ns = neti->netd_stack->nts_netstack;
    787 	ASSERT(ns != NULL);
    788 	return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip));
    789 }
    790 
    791 /*
    792  * Implement looking up an ill_t based on the name supplied and matching
    793  * it up with either IPv4 or IPv6.  ill_get_ifindex_by_name() is not used
    794  * because it does not match on the address family in addition to the name.
    795  */
    796 static phy_if_t
    797 ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst)
    798 {
    799 	phy_if_t phy;
    800 	ill_t *ill;
    801 
    802 	ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, ipst);
    803 	if (ill == NULL)
    804 		return (0);
    805 
    806 	phy = ill->ill_phyint->phyint_ifindex;
    807 
    808 	ill_refrele(ill);
    809 
    810 	return (phy);
    811 }
    812 
    813 /*
    814  * Get next interface from the current list of IPv4 logical network interfaces
    815  */
    816 static lif_if_t
    817 ip_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
    818 {
    819 	netstack_t *ns;
    820 
    821 	ns = neti->netd_stack->nts_netstack;
    822 	ASSERT(ns != NULL);
    823 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE,
    824 	    ns->netstack_ip));
    825 }
    826 
    827 /*
    828  * Get next interface from the current list of IPv6 logical network interfaces
    829  */
    830 static lif_if_t
    831 ipv6_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
    832 {
    833 	netstack_t *ns;
    834 
    835 	ns = neti->netd_stack->nts_netstack;
    836 	ASSERT(ns != NULL);
    837 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE,
    838 	    ns->netstack_ip));
    839 }
    840 
    841 /*
    842  * Shared implementation to get next interface from the current list of
    843  * logical network interfaces
    844  */
    845 static lif_if_t
    846 ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
    847     ip_stack_t *ipst)
    848 {
    849 	lif_if_t newidx, oldidx;
    850 	boolean_t nextok;
    851 	ipif_t *ipif;
    852 	ill_t *ill;
    853 
    854 	ill = ill_lookup_on_ifindex(phy_ifdata, isv6, ipst);
    855 	if (ill == NULL)
    856 		return (0);
    857 
    858 	if (ifdata != 0) {
    859 		oldidx = UNMAP_IPIF_ID(ifdata);
    860 		nextok = B_FALSE;
    861 	} else {
    862 		oldidx = 0;
    863 		nextok = B_TRUE;
    864 	}
    865 
    866 	mutex_enter(&ill->ill_lock);
    867 	if (ill->ill_state_flags & ILL_CONDEMNED) {
    868 		mutex_exit(&ill->ill_lock);
    869 		ill_refrele(ill);
    870 		return (0);
    871 	}
    872 
    873 	/*
    874 	 * It's safe to iterate the ill_ipif list when holding an ill_lock.
    875 	 * And it's also safe to access ipif_id without ipif refhold.
    876 	 * See the field access rules in ip.h.
    877 	 */
    878 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
    879 		if (!IPIF_CAN_LOOKUP(ipif))
    880 			continue;
    881 		if (nextok) {
    882 			ipif_refhold_locked(ipif);
    883 			break;
    884 		} else if (oldidx == ipif->ipif_id) {
    885 			nextok = B_TRUE;
    886 		}
    887 	}
    888 
    889 	mutex_exit(&ill->ill_lock);
    890 	ill_refrele(ill);
    891 
    892 	if (ipif == NULL)
    893 		return (0);
    894 
    895 	newidx = ipif->ipif_id;
    896 	ipif_refrele(ipif);
    897 
    898 	return (MAP_IPIF_ID(newidx));
    899 }
    900 
    901 /*
    902  * Inject an IPv4 packet to or from an interface
    903  */
    904 static int
    905 ip_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
    906 {
    907 	netstack_t *ns;
    908 
    909 	ns = neti->netd_stack->nts_netstack;
    910 	ASSERT(ns != NULL);
    911 	return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip));
    912 }
    913 
    914 
    915 /*
    916  * Inject an IPv6 packet to or from an interface
    917  */
    918 static int
    919 ipv6_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
    920 {
    921 	netstack_t *ns;
    922 
    923 	ns = neti->netd_stack->nts_netstack;
    924 	return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip));
    925 }
    926 
    927 /*
    928  * Shared implementation to inject a packet to or from an interface
    929  * Return value:
    930  *   0: successful
    931  *  -1: memory allocation failed
    932  *   1: other errors
    933  */
    934 static int
    935 ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6,
    936     ip_stack_t *ipst)
    937 {
    938 	ddi_taskq_t *tq = NULL;
    939 	void (* func)(void *);
    940 	injection_t *inject;
    941 	mblk_t *mp;
    942 
    943 	ASSERT(packet != NULL);
    944 	ASSERT(packet->ni_packet != NULL);
    945 	ASSERT(packet->ni_packet->b_datap->db_type == M_DATA);
    946 
    947 	switch (style) {
    948 	case NI_QUEUE_IN:
    949 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
    950 		if (inject == NULL)
    951 			return (-1);
    952 		inject->inj_data = *packet;
    953 		inject->inj_isv6 = isv6;
    954 		/*
    955 		 * deliver up into the kernel, immitating its reception by a
    956 		 * network interface, add to list and schedule timeout
    957 		 */
    958 		func = ip_ni_queue_in_func;
    959 		tq = eventq_queue_in;
    960 		break;
    961 
    962 	case NI_QUEUE_OUT:
    963 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
    964 		if (inject == NULL)
    965 			return (-1);
    966 		inject->inj_data = *packet;
    967 		inject->inj_isv6 = isv6;
    968 		/*
    969 		 * deliver out of the kernel, as if it were being sent via a
    970 		 * raw socket so that IPFilter will see it again, add to list
    971 		 * and schedule timeout
    972 		 */
    973 		func = ip_ni_queue_out_func;
    974 		tq = eventq_queue_out;
    975 		break;
    976 
    977 	case NI_DIRECT_OUT: {
    978 		struct sockaddr *sock;
    979 
    980 		mp = packet->ni_packet;
    981 
    982 		sock = (struct sockaddr *)&packet->ni_addr;
    983 		/*
    984 		 * ipfil_sendpkt was provided by surya to ease the
    985 		 * problems associated with sending out a packet.
    986 		 */
    987 		switch (ipfil_sendpkt(sock, mp, packet->ni_physical,
    988 		    netstackid_to_zoneid(
    989 		    ipst->ips_netstack->netstack_stackid))) {
    990 		case 0 :
    991 		case EINPROGRESS:
    992 			return (0);
    993 		case ECOMM :
    994 		case ENONET :
    995 			return (1);
    996 		default :
    997 			return (1);
    998 		}
    999 		/* NOTREACHED */
   1000 	}
   1001 	default:
   1002 		freemsg(packet->ni_packet);
   1003 		return (1);
   1004 	}
   1005 
   1006 	ASSERT(tq != NULL);
   1007 
   1008 	inject->inj_ptr = ipst;
   1009 	if (ddi_taskq_dispatch(tq, func, (void *)inject,
   1010 	    DDI_SLEEP) == DDI_FAILURE) {
   1011 		ip2dbg(("ip_inject:  ddi_taskq_dispatch failed\n"));
   1012 		freemsg(packet->ni_packet);
   1013 		return (1);
   1014 	}
   1015 	return (0);
   1016 }
   1017 
   1018 /*
   1019  * Find the interface used for traffic to a given IPv4 address
   1020  */
   1021 static phy_if_t
   1022 ip_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
   1023 {
   1024 	netstack_t *ns;
   1025 
   1026 	ASSERT(address != NULL);
   1027 
   1028 	if (address->sa_family != AF_INET)
   1029 		return (0);
   1030 
   1031 	ns = neti->netd_stack->nts_netstack;
   1032 	ASSERT(ns != NULL);
   1033 
   1034 	return (ip_routeto_impl(address, next, ns->netstack_ip));
   1035 }
   1036 
   1037 /*
   1038  * Find the interface used for traffic to a given IPv6 address
   1039  */
   1040 static phy_if_t
   1041 ipv6_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
   1042 {
   1043 	netstack_t *ns;
   1044 
   1045 	ASSERT(address != NULL);
   1046 
   1047 	if (address->sa_family != AF_INET6)
   1048 		return (0);
   1049 
   1050 	ns = neti->netd_stack->nts_netstack;
   1051 	ASSERT(ns != NULL);
   1052 
   1053 	return (ip_routeto_impl(address, next, ns->netstack_ip));
   1054 }
   1055 
   1056 
   1057 /*
   1058  * Find the interface used for traffic to an address.
   1059  * For lint reasons, next/next6/sin/sin6 are all declared and assigned
   1060  * a value at the top.  The alternative would end up with two bunches
   1061  * of assignments, with each bunch setting half to NULL.
   1062  */
   1063 static phy_if_t
   1064 ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop,
   1065     ip_stack_t *ipst)
   1066 {
   1067 	struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop;
   1068 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address;
   1069 	struct sockaddr_in *next = (struct sockaddr_in *)nexthop;
   1070 	struct sockaddr_in *sin = (struct sockaddr_in *)address;
   1071 	ire_t *ire;
   1072 	ire_t *nexthop_ire;
   1073 	phy_if_t phy_if;
   1074 	zoneid_t zoneid;
   1075 
   1076 	zoneid = netstackid_to_zoneid(ipst->ips_netstack->netstack_stackid);
   1077 
   1078 	if (address->sa_family == AF_INET6) {
   1079 		ire = ire_route_recursive_v6(&sin6->sin6_addr, 0, NULL,
   1080 		    zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst, NULL,
   1081 		    NULL, NULL);
   1082 	} else {
   1083 		ire = ire_route_recursive_v4(sin->sin_addr.s_addr, 0, NULL,
   1084 		    zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst, NULL,
   1085 		    NULL, NULL);
   1086 	}
   1087 	ASSERT(ire != NULL);
   1088 	/*
   1089 	 * For some destinations, we have routes that are dead ends, so
   1090 	 * return to indicate that no physical interface can be used to
   1091 	 * reach the destination.
   1092 	 */
   1093 	if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
   1094 		ire_refrele(ire);
   1095 		return (NULL);
   1096 	}
   1097 
   1098 	nexthop_ire = ire_nexthop(ire);
   1099 	if (nexthop_ire == NULL) {
   1100 		ire_refrele(ire);
   1101 		return (0);
   1102 	}
   1103 	if (nexthop_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
   1104 		ire_refrele(nexthop_ire);
   1105 		ire_refrele(ire);
   1106 		return (0);
   1107 	}
   1108 
   1109 	ASSERT(nexthop_ire->ire_ill != NULL);
   1110 
   1111 	if (nexthop != NULL) {
   1112 		if (address->sa_family == AF_INET6) {
   1113 			next6->sin6_addr = nexthop_ire->ire_addr_v6;
   1114 		} else {
   1115 			next->sin_addr.s_addr = nexthop_ire->ire_addr;
   1116 		}
   1117 	}
   1118 
   1119 	phy_if = (phy_if_t)nexthop_ire->ire_ill->ill_phyint->phyint_ifindex;
   1120 	ire_refrele(ire);
   1121 	ire_refrele(nexthop_ire);
   1122 
   1123 	return (phy_if);
   1124 }
   1125 
   1126 /*
   1127  * Determine if checksumming is being used for the given packet.
   1128  *
   1129  * Return value:
   1130  *   NET_HCK_NONE: full checksum recalculation is required
   1131  *   NET_HCK_L3_FULL: full layer 3 checksum
   1132  *   NET_HCK_L4_FULL: full layer 4 checksum
   1133  *   NET_HCK_L4_PART: partial layer 4 checksum
   1134  */
   1135 /*ARGSUSED*/
   1136 static int
   1137 ip_ispartialchecksum(net_handle_t neti, mblk_t *mp)
   1138 {
   1139 	int ret = 0;
   1140 
   1141 	ASSERT(mp != NULL);
   1142 
   1143 	if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) {
   1144 		ret |= (int)NET_HCK_L4_FULL;
   1145 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
   1146 			ret |= (int)NET_HCK_L3_FULL;
   1147 	}
   1148 	if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) {
   1149 		ret |= (int)NET_HCK_L4_PART;
   1150 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
   1151 			ret |= (int)NET_HCK_L3_FULL;
   1152 	}
   1153 
   1154 	return (ret);
   1155 }
   1156 
   1157 /*
   1158  * Return true or false, indicating whether the network and transport
   1159  * headers are correct.  Use the capabilities flags and flags set in the
   1160  * dblk_t to determine whether or not the checksum is valid.
   1161  *
   1162  * Return:
   1163  *   0: the checksum was incorrect
   1164  *   1: the original checksum was correct
   1165  */
   1166 /*ARGSUSED*/
   1167 static int
   1168 ip_isvalidchecksum(net_handle_t neti, mblk_t *mp)
   1169 {
   1170 	unsigned char *wptr;
   1171 	ipha_t *ipha = (ipha_t *)mp->b_rptr;
   1172 	int hlen;
   1173 	int ret;
   1174 
   1175 	ASSERT(mp != NULL);
   1176 
   1177 	if (dohwcksum &&
   1178 	    DB_CKSUM16(mp) != 0xFFFF &&
   1179 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) &&
   1180 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK) &&
   1181 	    (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM))
   1182 		return (1);
   1183 
   1184 	hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2;
   1185 
   1186 	/*
   1187 	 * Check that the mblk being passed in has enough data in it
   1188 	 * before blindly checking ip_cksum.
   1189 	 */
   1190 	if (msgdsize(mp) < hlen)
   1191 		return (0);
   1192 
   1193 	if (mp->b_wptr < mp->b_rptr + hlen) {
   1194 		if (pullupmsg(mp, hlen) == 0)
   1195 			return (0);
   1196 		wptr = mp->b_wptr;
   1197 	} else {
   1198 		wptr = mp->b_wptr;
   1199 		mp->b_wptr = mp->b_rptr + hlen;
   1200 	}
   1201 
   1202 	if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum))
   1203 		ret = 1;
   1204 	else
   1205 		ret = 0;
   1206 	mp->b_wptr = wptr;
   1207 
   1208 	return (ret);
   1209 }
   1210 
   1211 /*
   1212  * Unsupported with IPv6
   1213  */
   1214 /*ARGSUSED*/
   1215 static int
   1216 ipv6_isvalidchecksum(net_handle_t neti, mblk_t *mp)
   1217 {
   1218 	return (-1);
   1219 }
   1220 
   1221 /*
   1222  * Determine the network addresses for an IPv4 interface
   1223  */
   1224 static int
   1225 ip_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1226     size_t nelem, net_ifaddr_t type[], void *storage)
   1227 {
   1228 	netstack_t *ns;
   1229 
   1230 	ns = neti->netd_stack->nts_netstack;
   1231 	ASSERT(ns != NULL);
   1232 	return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata,
   1233 	    nelem, type, storage, ns->netstack_ip));
   1234 }
   1235 
   1236 /*
   1237  * Determine the network addresses for an IPv6 interface
   1238  */
   1239 static int
   1240 ipv6_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1241     size_t nelem, net_ifaddr_t type[], void *storage)
   1242 {
   1243 	netstack_t *ns;
   1244 
   1245 	ns = neti->netd_stack->nts_netstack;
   1246 	ASSERT(ns != NULL);
   1247 	return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata,
   1248 	    nelem, type, storage, ns->netstack_ip));
   1249 }
   1250 
   1251 /*
   1252  * Shared implementation to determine the network addresses for an interface
   1253  */
   1254 /* ARGSUSED */
   1255 static int
   1256 ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata,
   1257     lif_if_t ifdata, size_t nelem, net_ifaddr_t type[],
   1258     struct sockaddr *storage, ip_stack_t *ipst)
   1259 {
   1260 	struct sockaddr_in6 *sin6;
   1261 	struct sockaddr_in *sin;
   1262 	lif_if_t ipifid;
   1263 	ipif_t *ipif;
   1264 	int i;
   1265 
   1266 	ASSERT(type != NULL);
   1267 	ASSERT(storage != NULL);
   1268 
   1269 	ipifid = UNMAP_IPIF_ID(ifdata);
   1270 
   1271 	if (family == AF_INET) {
   1272 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
   1273 		    (uint_t)ipifid, B_FALSE, ipst)) == NULL)
   1274 			return (1);
   1275 
   1276 		sin = (struct sockaddr_in *)storage;
   1277 		for (i = 0; i < nelem; i++, sin++) {
   1278 			if (ip_getifaddr_type(AF_INET, ipif, type[i],
   1279 			    &sin->sin_addr) < 0) {
   1280 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
   1281 				    type[i]));
   1282 				ipif_refrele(ipif);
   1283 				return (1);
   1284 			}
   1285 			sin->sin_family = AF_INET;
   1286 		}
   1287 	} else {
   1288 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
   1289 		    (uint_t)ipifid, B_TRUE, ipst)) == NULL)
   1290 			return (1);
   1291 
   1292 		sin6 = (struct sockaddr_in6 *)storage;
   1293 		for (i = 0; i < nelem; i++, sin6++) {
   1294 			if (ip_getifaddr_type(AF_INET6, ipif, type[i],
   1295 			    &sin6->sin6_addr) < 0) {
   1296 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
   1297 				    type[i]));
   1298 				ipif_refrele(ipif);
   1299 				return (1);
   1300 			}
   1301 			sin6->sin6_family = AF_INET6;
   1302 		}
   1303 	}
   1304 	ipif_refrele(ipif);
   1305 	return (0);
   1306 }
   1307 
   1308 /*
   1309  * ip_getlifaddr private function
   1310  */
   1311 static int
   1312 ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif,
   1313     lif_if_t type, void *storage)
   1314 {
   1315 	void *src_addr;
   1316 	int mem_size;
   1317 
   1318 	ASSERT(ill_ipif != NULL);
   1319 	ASSERT(storage != NULL);
   1320 
   1321 	if (family == AF_INET) {
   1322 		mem_size = sizeof (struct in_addr);
   1323 
   1324 		switch (type) {
   1325 		case NA_ADDRESS:
   1326 			src_addr = &(ill_ipif->ipif_lcl_addr);
   1327 			break;
   1328 		case NA_PEER:
   1329 			src_addr = &(ill_ipif->ipif_pp_dst_addr);
   1330 			break;
   1331 		case NA_BROADCAST:
   1332 			src_addr = &(ill_ipif->ipif_brd_addr);
   1333 			break;
   1334 		case NA_NETMASK:
   1335 			src_addr = &(ill_ipif->ipif_net_mask);
   1336 			break;
   1337 		default:
   1338 			return (-1);
   1339 			/*NOTREACHED*/
   1340 		}
   1341 	} else {
   1342 		mem_size = sizeof (struct in6_addr);
   1343 
   1344 		switch (type) {
   1345 		case NA_ADDRESS:
   1346 			src_addr = &(ill_ipif->ipif_v6lcl_addr);
   1347 			break;
   1348 		case NA_PEER:
   1349 			src_addr = &(ill_ipif->ipif_v6pp_dst_addr);
   1350 			break;
   1351 		case NA_BROADCAST:
   1352 			src_addr = &(ill_ipif->ipif_v6brd_addr);
   1353 			break;
   1354 		case NA_NETMASK:
   1355 			src_addr = &(ill_ipif->ipif_v6net_mask);
   1356 			break;
   1357 		default:
   1358 			return (-1);
   1359 			/*NOTREACHED*/
   1360 		}
   1361 	}
   1362 
   1363 	(void) memcpy(storage, src_addr, mem_size);
   1364 	return (1);
   1365 }
   1366 
   1367 /*
   1368  * Shared implementation to determine the zoneid associated with an IPv4/IPv6
   1369  * address
   1370  */
   1371 static int
   1372 ip_getlifzone_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
   1373     ip_stack_t *ipst, zoneid_t *zoneid)
   1374 {
   1375 	ipif_t  *ipif;
   1376 
   1377 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
   1378 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
   1379 	if (ipif == NULL)
   1380 		return (-1);
   1381 	*zoneid = IP_REAL_ZONEID(ipif->ipif_zoneid, ipst);
   1382 	ipif_refrele(ipif);
   1383 	return (0);
   1384 }
   1385 
   1386 /*
   1387  * Determine the zoneid associated with an IPv4 address
   1388  */
   1389 static int
   1390 ip_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1391     zoneid_t *zoneid)
   1392 {
   1393 	return (ip_getlifzone_impl(AF_INET, phy_ifdata, ifdata,
   1394 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
   1395 }
   1396 
   1397 /*
   1398  * Determine the zoneid associated with an IPv6 address
   1399  */
   1400 static int
   1401 ipv6_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1402     zoneid_t *zoneid)
   1403 {
   1404 	return (ip_getlifzone_impl(AF_INET6, phy_ifdata, ifdata,
   1405 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
   1406 }
   1407 
   1408 /*
   1409  * The behaviour here mirrors that for the SIOCFLIFFLAGS ioctl where the
   1410  * union of all of the relevant flags is returned.
   1411  */
   1412 static int
   1413 ip_getlifflags_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
   1414     ip_stack_t *ipst, uint64_t *flags)
   1415 {
   1416 	phyint_t *phyi;
   1417 	ipif_t *ipif;
   1418 	ill_t *ill;
   1419 
   1420 	ill = ill_lookup_on_ifindex(phy_ifdata, (family == AF_INET6), ipst);
   1421 	if (ill == NULL)
   1422 		return (-1);
   1423 	phyi = ill->ill_phyint;
   1424 
   1425 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
   1426 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
   1427 	if (ipif == NULL) {
   1428 		ill_refrele(ill);
   1429 		return (-1);
   1430 	}
   1431 	*flags = ipif->ipif_flags | ill->ill_flags | phyi->phyint_flags;
   1432 	ipif_refrele(ipif);
   1433 	ill_refrele(ill);
   1434 	return (0);
   1435 }
   1436 
   1437 static int
   1438 ip_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1439     uint64_t *flags)
   1440 {
   1441 	return (ip_getlifflags_impl(AF_INET, phy_ifdata, ifdata,
   1442 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
   1443 }
   1444 
   1445 static int
   1446 ipv6_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1447     uint64_t *flags)
   1448 {
   1449 	return (ip_getlifflags_impl(AF_INET6, phy_ifdata, ifdata,
   1450 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
   1451 }
   1452 
   1453 /*
   1454  * Deliver packet up into the kernel, immitating its reception by a
   1455  * network interface.
   1456  */
   1457 static void
   1458 ip_ni_queue_in_func(void *inject)
   1459 {
   1460 	ip_ni_queue_func_impl(inject, B_FALSE);
   1461 }
   1462 
   1463 /*
   1464  * Deliver out of the kernel, as if it were being sent via a
   1465  * raw socket so that IPFilter will see it again.
   1466  */
   1467 static void
   1468 ip_ni_queue_out_func(void *inject)
   1469 {
   1470 	ip_ni_queue_func_impl(inject, B_TRUE);
   1471 }
   1472 
   1473 /*
   1474  * Shared implementation for inject via ip_output and ip_input
   1475  */
   1476 static void
   1477 ip_ni_queue_func_impl(injection_t *inject,  boolean_t out)
   1478 {
   1479 	net_inject_t *packet;
   1480 	ill_t *ill;
   1481 	ip_stack_t *ipst = (ip_stack_t *)inject->inj_ptr;
   1482 	ip_xmit_attr_t	ixas;
   1483 
   1484 	ASSERT(inject != NULL);
   1485 	packet = &inject->inj_data;
   1486 	ASSERT(packet->ni_packet != NULL);
   1487 
   1488 	if (out == 0) {
   1489 		ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical,
   1490 		    inject->inj_isv6, ipst);
   1491 
   1492 		if (ill == NULL) {
   1493 			kmem_free(inject, sizeof (*inject));
   1494 			return;
   1495 		}
   1496 
   1497 		if (inject->inj_isv6) {
   1498 			ip_input_v6(ill, NULL, packet->ni_packet, NULL);
   1499 		} else {
   1500 			ip_input(ill, NULL, packet->ni_packet, NULL);
   1501 		}
   1502 		ill_refrele(ill);
   1503 	} else {
   1504 		bzero(&ixas, sizeof (ixas));
   1505 		ixas.ixa_ifindex = packet->ni_physical;
   1506 		ixas.ixa_ipst = ipst;
   1507 		if (inject->inj_isv6) {
   1508 			ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
   1509 		} else {
   1510 			ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4;
   1511 		}
   1512 		(void) ip_output_simple(packet->ni_packet, &ixas);
   1513 		ixa_cleanup(&ixas);
   1514 	}
   1515 
   1516 	kmem_free(inject, sizeof (*inject));
   1517 }
   1518 
   1519 /*
   1520  * taskq function for nic events.
   1521  */
   1522 void
   1523 ip_ne_queue_func(void *arg)
   1524 {
   1525 	hook_event_token_t hr;
   1526 	hook_nic_event_int_t *info = (hook_nic_event_int_t *)arg;
   1527 	ip_stack_t *ipst;
   1528 	netstack_t *ns;
   1529 
   1530 	ns = netstack_find_by_stackid(info->hnei_stackid);
   1531 	if (ns == NULL)
   1532 		goto done;
   1533 
   1534 	ipst = ns->netstack_ip;
   1535 	if (ipst == NULL)
   1536 		goto done;
   1537 
   1538 	hr = (info->hnei_event.hne_protocol == ipst->ips_ipv6_net_data) ?
   1539 	    ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
   1540 	(void) hook_run(info->hnei_event.hne_protocol->netd_hooks, hr,
   1541 	    (hook_data_t)&info->hnei_event);
   1542 
   1543 done:
   1544 	if (ns != NULL)
   1545 		netstack_rele(ns);
   1546 	kmem_free(info->hnei_event.hne_data, info->hnei_event.hne_datalen);
   1547 	kmem_free(arg, sizeof (hook_nic_event_int_t));
   1548 }
   1549 
   1550 /*
   1551  * Initialize ARP hook family and events
   1552  */
   1553 void
   1554 arp_hook_init(ip_stack_t *ipst)
   1555 {
   1556 	HOOK_FAMILY_INIT(&ipst->ips_arproot, Hn_ARP);
   1557 	if (net_family_register(ipst->ips_arp_net_data, &ipst->ips_arproot)
   1558 	    != 0) {
   1559 		cmn_err(CE_NOTE, "arp_hook_init"
   1560 		    "net_family_register failed for arp");
   1561 	}
   1562 
   1563 	HOOK_EVENT_INIT(&ipst->ips_arp_physical_in_event, NH_PHYSICAL_IN);
   1564 	ipst->ips_arp_physical_in = net_event_register(ipst->ips_arp_net_data,
   1565 	    &ipst->ips_arp_physical_in_event);
   1566 	if (ipst->ips_arp_physical_in == NULL) {
   1567 		cmn_err(CE_NOTE, "arp_hook_init: "
   1568 		    "net_event_register failed for arp/physical_in");
   1569 	}
   1570 
   1571 	HOOK_EVENT_INIT(&ipst->ips_arp_physical_out_event, NH_PHYSICAL_OUT);
   1572 	ipst->ips_arp_physical_out = net_event_register(ipst->ips_arp_net_data,
   1573 	    &ipst->ips_arp_physical_out_event);
   1574 	if (ipst->ips_arp_physical_out == NULL) {
   1575 		cmn_err(CE_NOTE, "arp_hook_init: "
   1576 		    "net_event_register failed for arp/physical_out");
   1577 	}
   1578 
   1579 	HOOK_EVENT_INIT(&ipst->ips_arp_nic_events, NH_NIC_EVENTS);
   1580 	ipst->ips_arpnicevents = net_event_register(ipst->ips_arp_net_data,
   1581 	    &ipst->ips_arp_nic_events);
   1582 	if (ipst->ips_arpnicevents == NULL) {
   1583 		cmn_err(CE_NOTE, "arp_hook_init: "
   1584 		    "net_event_register failed for arp/nic_events");
   1585 	}
   1586 }
   1587 
   1588 void
   1589 arp_hook_destroy(ip_stack_t *ipst)
   1590 {
   1591 	if (ipst->ips_arpnicevents != NULL) {
   1592 		if (net_event_unregister(ipst->ips_arp_net_data,
   1593 		    &ipst->ips_arp_nic_events) == 0)
   1594 			ipst->ips_arpnicevents = NULL;
   1595 	}
   1596 
   1597 	if (ipst->ips_arp_physical_out != NULL) {
   1598 		if (net_event_unregister(ipst->ips_arp_net_data,
   1599 		    &ipst->ips_arp_physical_out_event) == 0)
   1600 			ipst->ips_arp_physical_out = NULL;
   1601 	}
   1602 
   1603 	if (ipst->ips_arp_physical_in != NULL) {
   1604 		if (net_event_unregister(ipst->ips_arp_net_data,
   1605 		    &ipst->ips_arp_physical_in_event) == 0)
   1606 			ipst->ips_arp_physical_in = NULL;
   1607 	}
   1608 
   1609 	(void) net_family_unregister(ipst->ips_arp_net_data,
   1610 	    &ipst->ips_arproot);
   1611 }
   1612 
   1613 void
   1614 arp_hook_shutdown(ip_stack_t *ipst)
   1615 {
   1616 	if (ipst->ips_arp_physical_in != NULL) {
   1617 		(void) net_event_shutdown(ipst->ips_arp_net_data,
   1618 		    &ipst->ips_arp_physical_in_event);
   1619 	}
   1620 	if (ipst->ips_arp_physical_out != NULL) {
   1621 		(void) net_event_shutdown(ipst->ips_arp_net_data,
   1622 		    &ipst->ips_arp_physical_out_event);
   1623 	}
   1624 	if (ipst->ips_arpnicevents != NULL) {
   1625 		(void) net_event_shutdown(ipst->ips_arp_net_data,
   1626 		    &ipst->ips_arp_nic_events);
   1627 	}
   1628 }
   1629 
   1630 /* netinfo routines for the unsupported cases */
   1631 
   1632 /* ARGSUSED */
   1633 int
   1634 net_no_getmtu(net_handle_t handle, phy_if_t phy_ifdata, lif_if_t ifdata)
   1635 {
   1636 	return (-1);
   1637 }
   1638 
   1639 /* ARGSUSED */
   1640 static int
   1641 net_no_getpmtuenabled(net_handle_t neti)
   1642 {
   1643 	return (-1);
   1644 }
   1645 
   1646 /* ARGSUSED */
   1647 static lif_if_t
   1648 net_no_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
   1649 {
   1650 	return (-1);
   1651 }
   1652 
   1653 /* ARGSUSED */
   1654 static int
   1655 net_no_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
   1656 {
   1657 	return (-1);
   1658 }
   1659 
   1660 /* ARGSUSED */
   1661 static phy_if_t
   1662 net_no_routeto(net_handle_t neti, struct sockaddr *address,
   1663     struct sockaddr *next)
   1664 {
   1665 	return ((phy_if_t)-1);
   1666 }
   1667 
   1668 /* ARGSUSED */
   1669 static int
   1670 net_no_ispartialchecksum(net_handle_t neti, mblk_t *mp)
   1671 {
   1672 	return (-1);
   1673 }
   1674 
   1675 /* ARGSUSED */
   1676 static int
   1677 net_no_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1678     size_t nelem, net_ifaddr_t type[], void *storage)
   1679 {
   1680 	return (-1);
   1681 }
   1682 
   1683 /* ARGSUSED */
   1684 static int
   1685 net_no_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1686     zoneid_t *zoneid)
   1687 {
   1688 	return (-1);
   1689 }
   1690 
   1691 /* ARGSUSED */
   1692 static int
   1693 net_no_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
   1694     uint64_t *flags)
   1695 {
   1696 	return (-1);
   1697 }
   1698