xref: /titanic_41/usr/src/uts/common/inet/ip/ip_netinfo.c (revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6)
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