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