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