xref: /illumos-gate/usr/src/uts/common/inet/ip/ip_netinfo.c (revision b424305435881ac456a9343be2898f1f86440f31)
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 2008 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 	char *name;
572 
573 	ASSERT(buffer != NULL);
574 
575 	ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, NULL, NULL,
576 	    NULL, NULL, ipst);
577 	if (ill != NULL) {
578 		name = ill->ill_name;
579 	} else {
580 		/* Fallback to group names only if hook_emulation is set */
581 		if (ipst->ips_ipmp_hook_emulation) {
582 			ill = ill_group_lookup_on_ifindex((uint_t)phy_ifdata,
583 			    isv6, ipst);
584 		}
585 		if (ill == NULL)
586 			return (1);
587 		name = ill->ill_phyint->phyint_groupname;
588 	}
589 	if (name != NULL) {
590 		(void) strlcpy(buffer, name, buflen);
591 		ill_refrele(ill);
592 		return (0);
593 	} else {
594 		ill_refrele(ill);
595 		return (1);
596 	}
597 
598 }
599 
600 /*
601  * Determine the MTU of an IPv4 network interface
602  */
603 static int
604 ip_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
605 {
606 	netstack_t *ns;
607 
608 	ns = neti->netd_stack->nts_netstack;
609 	ASSERT(ns != NULL);
610 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip));
611 }
612 
613 /*
614  * Determine the MTU of an IPv6 network interface
615  */
616 static int
617 ipv6_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
618 {
619 	netstack_t *ns;
620 
621 	ns = neti->netd_stack->nts_netstack;
622 	ASSERT(ns != NULL);
623 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip));
624 }
625 
626 /*
627  * Shared implementation to determine the MTU of a network interface
628  *
629  * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
630  * But IP Filter only uses a zero ifdata.
631  */
632 /* ARGSUSED */
633 static int
634 ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
635     ip_stack_t *ipst)
636 {
637 	lif_if_t ipifid;
638 	ipif_t *ipif;
639 	int mtu;
640 
641 	ipifid = UNMAP_IPIF_ID(ifdata);
642 
643 	ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid,
644 	    isv6, ipst);
645 	if (ipif == NULL)
646 		return (0);
647 
648 	mtu = ipif->ipif_mtu;
649 	ipif_refrele(ipif);
650 
651 	if (mtu == 0) {
652 		ill_t *ill;
653 
654 		if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6,
655 		    NULL, NULL, NULL, NULL, ipst)) == NULL) {
656 			/*
657 			 * Fallback to group names only if hook_emulation
658 			 * is set
659 			 */
660 			if (ipst->ips_ipmp_hook_emulation) {
661 				ill = ill_group_lookup_on_ifindex(
662 				    (uint_t)phy_ifdata, isv6, ipst);
663 			}
664 			if (ill == NULL)
665 				return (0);
666 		}
667 		mtu = ill->ill_max_frag;
668 		ill_refrele(ill);
669 	}
670 
671 	return (mtu);
672 }
673 
674 /*
675  * Determine if path MTU discovery is enabled for IP
676  */
677 static int
678 ip_getpmtuenabled(net_handle_t neti)
679 {
680 	netstack_t *ns;
681 
682 	ns = neti->netd_stack->nts_netstack;
683 	ASSERT(ns != NULL);
684 	return (ns->netstack_ip->ips_ip_path_mtu_discovery);
685 }
686 
687 /*
688  * Get next interface from the current list of IPv4 physical network interfaces
689  *
690  * Note: this does not handle the case when ipmp_hook_emulation is set.
691  * But IP Filter does not use this function.
692  */
693 static phy_if_t
694 ip_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
695 {
696 	netstack_t *ns;
697 
698 	ns = neti->netd_stack->nts_netstack;
699 	ASSERT(ns != NULL);
700 	return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip));
701 }
702 
703 /*
704  * Get next interface from the current list of IPv6 physical network interfaces
705  */
706 static phy_if_t
707 ipv6_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
708 {
709 	netstack_t *ns;
710 
711 	ns = neti->netd_stack->nts_netstack;
712 	ASSERT(ns != NULL);
713 	return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip));
714 }
715 
716 /*
717  * Determine if a network interface name exists for IPv4
718  */
719 static phy_if_t
720 ip_phylookup(net_handle_t neti, const char *name)
721 {
722 	netstack_t *ns;
723 
724 	ns = neti->netd_stack->nts_netstack;
725 	ASSERT(ns != NULL);
726 	return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip));
727 }
728 
729 /*
730  * Determine if a network interface name exists for IPv6
731  */
732 static phy_if_t
733 ipv6_phylookup(net_handle_t neti, const char *name)
734 {
735 	netstack_t *ns;
736 
737 	ns = neti->netd_stack->nts_netstack;
738 	ASSERT(ns != NULL);
739 	return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip));
740 }
741 
742 /*
743  * Implement looking up an ill_t based on the name supplied and matching
744  * it up with either IPv4 or IPv6.  ill_get_ifindex_by_name() is not used
745  * because it does not match on the address family in addition to the name.
746  */
747 static phy_if_t
748 ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst)
749 {
750 	phy_if_t phy;
751 	ill_t *ill;
752 
753 	ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, NULL,
754 	    NULL, NULL, NULL, ipst);
755 
756 	/* Fallback to group names only if hook_emulation is set */
757 	if (ill == NULL && ipst->ips_ipmp_hook_emulation) {
758 		ill = ill_group_lookup_on_name((char *)name, isv6, ipst);
759 	}
760 	if (ill == NULL)
761 		return (0);
762 
763 	phy = ill->ill_phyint->phyint_hook_ifindex;
764 
765 	ill_refrele(ill);
766 
767 	return (phy);
768 }
769 
770 /*
771  * Get next interface from the current list of IPv4 logical network interfaces
772  */
773 static lif_if_t
774 ip_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
775 {
776 	netstack_t *ns;
777 
778 	ns = neti->netd_stack->nts_netstack;
779 	ASSERT(ns != NULL);
780 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE,
781 	    ns->netstack_ip));
782 }
783 
784 /*
785  * Get next interface from the current list of IPv6 logical network interfaces
786  */
787 static lif_if_t
788 ipv6_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
789 {
790 	netstack_t *ns;
791 
792 	ns = neti->netd_stack->nts_netstack;
793 	ASSERT(ns != NULL);
794 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE,
795 	    ns->netstack_ip));
796 }
797 
798 /*
799  * Shared implementation to get next interface from the current list of
800  * logical network interfaces
801  *
802  * Note: this does not handle the case when ipmp_hook_emulation is set.
803  * But IP Filter does not use this function.
804  */
805 static lif_if_t
806 ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
807     ip_stack_t *ipst)
808 {
809 	lif_if_t newidx, oldidx;
810 	boolean_t nextok;
811 	ipif_t *ipif;
812 	ill_t *ill;
813 
814 	ill = ill_lookup_on_ifindex(phy_ifdata, isv6, NULL, NULL,
815 	    NULL, NULL, ipst);
816 	if (ill == NULL)
817 		return (0);
818 
819 	if (ifdata != 0) {
820 		oldidx = UNMAP_IPIF_ID(ifdata);
821 		nextok = B_FALSE;
822 	} else {
823 		oldidx = 0;
824 		nextok = B_TRUE;
825 	}
826 
827 	mutex_enter(&ill->ill_lock);
828 	if (ill->ill_state_flags & ILL_CONDEMNED) {
829 		mutex_exit(&ill->ill_lock);
830 		ill_refrele(ill);
831 		return (0);
832 	}
833 
834 	/*
835 	 * It's safe to iterate the ill_ipif list when holding an ill_lock.
836 	 * And it's also safe to access ipif_id without ipif refhold.
837 	 * See ipif_get_id().
838 	 */
839 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
840 		if (!IPIF_CAN_LOOKUP(ipif))
841 			continue;
842 		if (nextok) {
843 			ipif_refhold_locked(ipif);
844 			break;
845 		} else if (oldidx == ipif->ipif_id) {
846 			nextok = B_TRUE;
847 		}
848 	}
849 
850 	mutex_exit(&ill->ill_lock);
851 	ill_refrele(ill);
852 
853 	if (ipif == NULL)
854 		return (0);
855 
856 	newidx = ipif->ipif_id;
857 	ipif_refrele(ipif);
858 
859 	return (MAP_IPIF_ID(newidx));
860 }
861 
862 /*
863  * Inject an IPv4 packet to or from an interface
864  */
865 static int
866 ip_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
867 {
868 	netstack_t *ns;
869 
870 	ns = neti->netd_stack->nts_netstack;
871 	ASSERT(ns != NULL);
872 	return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip));
873 }
874 
875 
876 /*
877  * Inject an IPv6 packet to or from an interface
878  */
879 static int
880 ipv6_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
881 {
882 	netstack_t *ns;
883 
884 	ns = neti->netd_stack->nts_netstack;
885 	return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip));
886 }
887 
888 /*
889  * Shared implementation to inject a packet to or from an interface
890  * Return value:
891  *   0: successful
892  *  -1: memory allocation failed
893  *   1: other errors
894  */
895 static int
896 ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6,
897     ip_stack_t *ipst)
898 {
899 	struct sockaddr_in6 *sin6;
900 	ddi_taskq_t *tq = NULL;
901 	void (* func)(void *);
902 	injection_t *inject;
903 	ip6_t *ip6h;
904 	ire_t *ire;
905 	mblk_t *mp;
906 	zoneid_t zoneid;
907 
908 	ASSERT(packet != NULL);
909 	ASSERT(packet->ni_packet != NULL);
910 	ASSERT(packet->ni_packet->b_datap->db_type == M_DATA);
911 
912 	switch (style) {
913 	case NI_QUEUE_IN:
914 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
915 		if (inject == NULL)
916 			return (-1);
917 		inject->inj_data = *packet;
918 		inject->inj_isv6 = isv6;
919 		/*
920 		 * deliver up into the kernel, immitating its reception by a
921 		 * network interface, add to list and schedule timeout
922 		 */
923 		func = ip_ni_queue_in_func;
924 		tq = eventq_queue_in;
925 		break;
926 
927 	case NI_QUEUE_OUT:
928 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
929 		if (inject == NULL)
930 			return (-1);
931 		inject->inj_data = *packet;
932 		inject->inj_isv6 = isv6;
933 		/*
934 		 * deliver out of the kernel, as if it were being sent via a
935 		 * raw socket so that IPFilter will see it again, add to list
936 		 * and schedule timeout
937 		 */
938 		func = ip_ni_queue_out_func;
939 		tq = eventq_queue_out;
940 		break;
941 
942 	case NI_DIRECT_OUT:
943 		/*
944 		 * Note:
945 		 * For IPv4, the code path below will be greatly simplified
946 		 * with the delivery of surya - it will become a single
947 		 * function call to X.  A follow on project is aimed to
948 		 * provide similar functionality for IPv6.
949 		 */
950 		mp = packet->ni_packet;
951 		zoneid =
952 		    netstackid_to_zoneid(ipst->ips_netstack->netstack_stackid);
953 
954 		if (!isv6) {
955 			struct sockaddr *sock;
956 
957 			sock = (struct sockaddr *)&packet->ni_addr;
958 			/*
959 			 * ipfil_sendpkt was provided by surya to ease the
960 			 * problems associated with sending out a packet.
961 			 * Currently this function only supports IPv4.
962 			 */
963 			switch (ipfil_sendpkt(sock, mp, packet->ni_physical,
964 			    zoneid)) {
965 			case 0 :
966 			case EINPROGRESS:
967 				return (0);
968 			case ECOMM :
969 			case ENONET :
970 				return (1);
971 			default :
972 				return (1);
973 			}
974 			/* NOTREACHED */
975 
976 		}
977 
978 		ip6h = (ip6_t *)mp->b_rptr;
979 		sin6 = (struct sockaddr_in6 *)&packet->ni_addr;
980 		ASSERT(sin6->sin6_family == AF_INET6);
981 
982 		ire = ire_route_lookup_v6(&sin6->sin6_addr, 0, 0, 0,
983 		    NULL, NULL, ALL_ZONES, NULL,
984 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
985 		    ipst);
986 
987 		if (ire == NULL) {
988 			ip2dbg(("ip_inject: ire_cache_lookup failed\n"));
989 			freemsg(mp);
990 			return (1);
991 		}
992 
993 		if (ire->ire_stq == NULL) {
994 			/* Send to loopback destination. */
995 			if (ire->ire_rfq == NULL) {
996 				ip2dbg(("ip_inject: bad nexthop\n"));
997 				ire_refrele(ire);
998 				freemsg(mp);
999 				return (1);
1000 			}
1001 			DTRACE_IP7(send, mblk_t *, mp, conn_t *, NULL,
1002 			    void_ip_t *, ip6h, __dtrace_ipsr_ill_t *,
1003 			    ire->ire_ipif->ipif_ill, ipha_t *, NULL, ip6_t *,
1004 			    ip6h, int, 1);
1005 			ip_wput_local_v6(ire->ire_rfq,
1006 			    ire->ire_ipif->ipif_ill, ip6h, mp, ire, 0, zoneid);
1007 			ire_refrele(ire);
1008 			return (0);
1009 		}
1010 
1011 		mp->b_queue = ire->ire_stq;
1012 
1013 		if (ire->ire_nce == NULL ||
1014 		    ire->ire_nce->nce_fp_mp == NULL &&
1015 		    ire->ire_nce->nce_res_mp == NULL) {
1016 			ip_newroute_v6(ire->ire_stq, mp,
1017 			    &sin6->sin6_addr, NULL, NULL, ALL_ZONES, ipst);
1018 
1019 			ire_refrele(ire);
1020 			return (0);
1021 		} else {
1022 			/* prepend L2 header for IPv6 packets. */
1023 			mblk_t *llmp;
1024 
1025 			/*
1026 			 * Lock IREs, see 6420438
1027 			 */
1028 			mutex_enter(&ire->ire_lock);
1029 			llmp = ire->ire_nce->nce_fp_mp ?
1030 			    ire->ire_nce->nce_fp_mp :
1031 			    ire->ire_nce->nce_res_mp;
1032 
1033 			if ((mp = dupb(llmp)) == NULL &&
1034 			    (mp = copyb(llmp)) == NULL) {
1035 				ip2dbg(("ip_inject: llhdr failed\n"));
1036 				mutex_exit(&ire->ire_lock);
1037 				ire_refrele(ire);
1038 				freemsg(mp);
1039 				return (1);
1040 			}
1041 			mutex_exit(&ire->ire_lock);
1042 			linkb(mp, packet->ni_packet);
1043 		}
1044 
1045 		mp->b_queue = ire->ire_stq;
1046 
1047 		break;
1048 	default:
1049 		freemsg(packet->ni_packet);
1050 		return (1);
1051 	}
1052 
1053 	if (tq) {
1054 		inject->inj_ptr = ipst;
1055 		if (ddi_taskq_dispatch(tq, func, (void *)inject,
1056 		    DDI_SLEEP) == DDI_FAILURE) {
1057 			ip2dbg(("ip_inject:  ddi_taskq_dispatch failed\n"));
1058 			freemsg(packet->ni_packet);
1059 			return (1);
1060 		}
1061 	} else {
1062 		putnext(ire->ire_stq, mp);
1063 		ire_refrele(ire);
1064 	}
1065 
1066 	return (0);
1067 }
1068 
1069 /*
1070  * Find the interface used for traffic to a given IPv4 address
1071  */
1072 static phy_if_t
1073 ip_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
1074 {
1075 	netstack_t *ns;
1076 
1077 	ASSERT(address != NULL);
1078 
1079 	if (address->sa_family != AF_INET)
1080 		return (0);
1081 
1082 	ns = neti->netd_stack->nts_netstack;
1083 	ASSERT(ns != NULL);
1084 
1085 	return (ip_routeto_impl(address, next, ns->netstack_ip));
1086 }
1087 
1088 /*
1089  * Find the interface used for traffic to a given IPv6 address
1090  */
1091 static phy_if_t
1092 ipv6_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
1093 {
1094 	netstack_t *ns;
1095 
1096 	ASSERT(address != NULL);
1097 
1098 	if (address->sa_family != AF_INET6)
1099 		return (0);
1100 
1101 	ns = neti->netd_stack->nts_netstack;
1102 	ASSERT(ns != NULL);
1103 
1104 	return (ip_routeto_impl(address, next, ns->netstack_ip));
1105 }
1106 
1107 
1108 /*
1109  * Find the interface used for traffic to an address.
1110  * For lint reasons, next/next6/sin/sin6 are all declared and assigned
1111  * a value at the top.  The alternative would end up with two bunches
1112  * of assignments, with each bunch setting half to NULL.
1113  */
1114 static phy_if_t
1115 ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop,
1116     ip_stack_t *ipst)
1117 {
1118 	struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop;
1119 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address;
1120 	struct sockaddr_in *next = (struct sockaddr_in *)nexthop;
1121 	struct sockaddr_in *sin = (struct sockaddr_in *)address;
1122 	ire_t *sire = NULL;
1123 	ire_t *ire;
1124 	ill_t *ill;
1125 	phy_if_t phy_if;
1126 
1127 	if (address->sa_family == AF_INET6) {
1128 		ire = ire_route_lookup_v6(&sin6->sin6_addr, NULL,
1129 		    0, 0, NULL, &sire, ALL_ZONES, NULL,
1130 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
1131 		    ipst);
1132 	} else {
1133 		ire = ire_route_lookup(sin->sin_addr.s_addr, 0,
1134 		    0, 0, NULL, &sire, ALL_ZONES, NULL,
1135 		    MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
1136 		    ipst);
1137 	}
1138 
1139 	if (ire == NULL)
1140 		return (0);
1141 
1142 	/*
1143 	 * For some destinations, we have routes that are dead ends, so
1144 	 * return to indicate that no physical interface can be used to
1145 	 * reach the destination.
1146 	 */
1147 	if ((ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE)) != 0) {
1148 		if (sire != NULL)
1149 			ire_refrele(sire);
1150 		ire_refrele(ire);
1151 		return (0);
1152 	}
1153 
1154 	ill = ire_to_ill(ire);
1155 	if (ill == NULL) {
1156 		if (sire != NULL)
1157 			ire_refrele(sire);
1158 		ire_refrele(ire);
1159 		return (0);
1160 	}
1161 
1162 	if (nexthop != NULL) {
1163 		if (address->sa_family == AF_INET6) {
1164 			next->sin_addr.s_addr = sire ? sire->ire_gateway_addr :
1165 			    sin->sin_addr.s_addr;
1166 		} else {
1167 			next6->sin6_addr = sire ? sire->ire_gateway_addr_v6 :
1168 			    sin6->sin6_addr;
1169 		}
1170 	}
1171 
1172 	ASSERT(ill != NULL);
1173 	phy_if = (phy_if_t)ill->ill_phyint->phyint_hook_ifindex;
1174 	if (sire != NULL)
1175 		ire_refrele(sire);
1176 	ire_refrele(ire);
1177 
1178 	return (phy_if);
1179 }
1180 
1181 /*
1182  * Determine if checksumming is being used for the given packet.
1183  *
1184  * Return value:
1185  *   NET_HCK_NONE: full checksum recalculation is required
1186  *   NET_HCK_L3_FULL: full layer 3 checksum
1187  *   NET_HCK_L4_FULL: full layer 4 checksum
1188  *   NET_HCK_L4_PART: partial layer 4 checksum
1189  */
1190 /*ARGSUSED*/
1191 static int
1192 ip_ispartialchecksum(net_handle_t neti, mblk_t *mp)
1193 {
1194 	int ret = 0;
1195 
1196 	ASSERT(mp != NULL);
1197 
1198 	if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) {
1199 		ret |= (int)NET_HCK_L4_FULL;
1200 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
1201 			ret |= (int)NET_HCK_L3_FULL;
1202 	}
1203 	if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) {
1204 		ret |= (int)NET_HCK_L4_PART;
1205 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
1206 			ret |= (int)NET_HCK_L3_FULL;
1207 	}
1208 
1209 	return (ret);
1210 }
1211 
1212 /*
1213  * Return true or false, indicating whether the network and transport
1214  * headers are correct.  Use the capabilities flags and flags set in the
1215  * dblk_t to determine whether or not the checksum is valid.
1216  *
1217  * Return:
1218  *   0: the checksum was incorrect
1219  *   1: the original checksum was correct
1220  */
1221 /*ARGSUSED*/
1222 static int
1223 ip_isvalidchecksum(net_handle_t neti, mblk_t *mp)
1224 {
1225 	unsigned char *wptr;
1226 	ipha_t *ipha = (ipha_t *)mp->b_rptr;
1227 	int hlen;
1228 	int ret;
1229 
1230 	ASSERT(mp != NULL);
1231 
1232 	if (dohwcksum &&
1233 	    DB_CKSUM16(mp) != 0xFFFF &&
1234 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) &&
1235 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK) &&
1236 	    (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM))
1237 		return (1);
1238 
1239 	hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2;
1240 
1241 	/*
1242 	 * Check that the mblk being passed in has enough data in it
1243 	 * before blindly checking ip_cksum.
1244 	 */
1245 	if (msgdsize(mp) < hlen)
1246 		return (0);
1247 
1248 	if (mp->b_wptr < mp->b_rptr + hlen) {
1249 		if (pullupmsg(mp, hlen) == 0)
1250 			return (0);
1251 		wptr = mp->b_wptr;
1252 	} else {
1253 		wptr = mp->b_wptr;
1254 		mp->b_wptr = mp->b_rptr + hlen;
1255 	}
1256 
1257 	if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum))
1258 		ret = 1;
1259 	else
1260 		ret = 0;
1261 	mp->b_wptr = wptr;
1262 
1263 	return (ret);
1264 }
1265 
1266 /*
1267  * Unsupported with IPv6
1268  */
1269 /*ARGSUSED*/
1270 static int
1271 ipv6_isvalidchecksum(net_handle_t neti, mblk_t *mp)
1272 {
1273 	return (-1);
1274 }
1275 
1276 /*
1277  * Determine the network addresses for an IPv4 interface
1278  */
1279 static int
1280 ip_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1281     size_t nelem, net_ifaddr_t type[], void *storage)
1282 {
1283 	netstack_t *ns;
1284 
1285 	ns = neti->netd_stack->nts_netstack;
1286 	ASSERT(ns != NULL);
1287 	return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata,
1288 	    nelem, type, storage, ns->netstack_ip));
1289 }
1290 
1291 /*
1292  * Determine the network addresses for an IPv6 interface
1293  */
1294 static int
1295 ipv6_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1296     size_t nelem, net_ifaddr_t type[], void *storage)
1297 {
1298 	netstack_t *ns;
1299 
1300 	ns = neti->netd_stack->nts_netstack;
1301 	ASSERT(ns != NULL);
1302 	return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata,
1303 	    nelem, type, storage, ns->netstack_ip));
1304 }
1305 
1306 /*
1307  * Shared implementation to determine the network addresses for an interface
1308  *
1309  * Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
1310  * But IP Filter only uses a zero ifdata.
1311  */
1312 /* ARGSUSED */
1313 static int
1314 ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata,
1315     lif_if_t ifdata, size_t nelem, net_ifaddr_t type[],
1316     struct sockaddr *storage, ip_stack_t *ipst)
1317 {
1318 	struct sockaddr_in6 *sin6;
1319 	struct sockaddr_in *sin;
1320 	lif_if_t ipifid;
1321 	ipif_t *ipif;
1322 	int i;
1323 
1324 	ASSERT(type != NULL);
1325 	ASSERT(storage != NULL);
1326 
1327 	ipifid = UNMAP_IPIF_ID(ifdata);
1328 
1329 	if (family == AF_INET) {
1330 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1331 		    (uint_t)ipifid, B_FALSE, ipst)) == NULL)
1332 			return (1);
1333 
1334 		sin = (struct sockaddr_in *)storage;
1335 		for (i = 0; i < nelem; i++, sin++) {
1336 			if (ip_getifaddr_type(AF_INET, ipif, type[i],
1337 			    &sin->sin_addr) < 0) {
1338 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
1339 				    type[i]));
1340 				ipif_refrele(ipif);
1341 				return (1);
1342 			}
1343 			sin->sin_family = AF_INET;
1344 		}
1345 	} else {
1346 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1347 		    (uint_t)ipifid, B_TRUE, ipst)) == NULL)
1348 			return (1);
1349 
1350 		sin6 = (struct sockaddr_in6 *)storage;
1351 		for (i = 0; i < nelem; i++, sin6++) {
1352 			if (ip_getifaddr_type(AF_INET6, ipif, type[i],
1353 			    &sin6->sin6_addr) < 0) {
1354 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
1355 				    type[i]));
1356 				ipif_refrele(ipif);
1357 				return (1);
1358 			}
1359 			sin6->sin6_family = AF_INET6;
1360 		}
1361 	}
1362 	ipif_refrele(ipif);
1363 	return (0);
1364 }
1365 
1366 /*
1367  * ip_getlifaddr private function
1368  */
1369 static int
1370 ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif,
1371     lif_if_t type, void *storage)
1372 {
1373 	void *src_addr;
1374 	int mem_size;
1375 
1376 	ASSERT(ill_ipif != NULL);
1377 	ASSERT(storage != NULL);
1378 
1379 	if (family == AF_INET) {
1380 		mem_size = sizeof (struct in_addr);
1381 
1382 		switch (type) {
1383 		case NA_ADDRESS:
1384 			src_addr = &(ill_ipif->ipif_lcl_addr);
1385 			break;
1386 		case NA_PEER:
1387 			src_addr = &(ill_ipif->ipif_pp_dst_addr);
1388 			break;
1389 		case NA_BROADCAST:
1390 			src_addr = &(ill_ipif->ipif_brd_addr);
1391 			break;
1392 		case NA_NETMASK:
1393 			src_addr = &(ill_ipif->ipif_net_mask);
1394 			break;
1395 		default:
1396 			return (-1);
1397 			/*NOTREACHED*/
1398 		}
1399 	} else {
1400 		mem_size = sizeof (struct in6_addr);
1401 
1402 		switch (type) {
1403 		case NA_ADDRESS:
1404 			src_addr = &(ill_ipif->ipif_v6lcl_addr);
1405 			break;
1406 		case NA_PEER:
1407 			src_addr = &(ill_ipif->ipif_v6pp_dst_addr);
1408 			break;
1409 		case NA_BROADCAST:
1410 			src_addr = &(ill_ipif->ipif_v6brd_addr);
1411 			break;
1412 		case NA_NETMASK:
1413 			src_addr = &(ill_ipif->ipif_v6net_mask);
1414 			break;
1415 		default:
1416 			return (-1);
1417 			/*NOTREACHED*/
1418 		}
1419 	}
1420 
1421 	(void) memcpy(storage, src_addr, mem_size);
1422 	return (1);
1423 }
1424 
1425 /*
1426  * Shared implementation to determine the zoneid associated with an IPv4/IPv6
1427  * address
1428  */
1429 static int
1430 ip_getlifzone_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
1431     ip_stack_t *ipst, zoneid_t *zoneid)
1432 {
1433 	ipif_t  *ipif;
1434 
1435 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1436 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
1437 	if (ipif == NULL)
1438 		return (-1);
1439 	*zoneid = IP_REAL_ZONEID(ipif->ipif_zoneid, ipst);
1440 	ipif_refrele(ipif);
1441 	return (0);
1442 }
1443 
1444 /*
1445  * Determine the zoneid associated with an IPv4 address
1446  */
1447 static int
1448 ip_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1449     zoneid_t *zoneid)
1450 {
1451 	return (ip_getlifzone_impl(AF_INET, phy_ifdata, ifdata,
1452 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
1453 }
1454 
1455 /*
1456  * Determine the zoneid associated with an IPv6 address
1457  */
1458 static int
1459 ipv6_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1460     zoneid_t *zoneid)
1461 {
1462 	return (ip_getlifzone_impl(AF_INET6, phy_ifdata, ifdata,
1463 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
1464 }
1465 
1466 static int
1467 ip_getlifflags_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
1468     ip_stack_t *ipst, uint64_t *flags)
1469 {
1470 	ipif_t *ipif;
1471 
1472 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1473 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
1474 	if (ipif == NULL)
1475 		return (-1);
1476 	*flags = ipif->ipif_flags;
1477 	ipif_refrele(ipif);
1478 	return (0);
1479 }
1480 
1481 static int
1482 ip_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1483     uint64_t *flags)
1484 {
1485 	return (ip_getlifflags_impl(AF_INET, phy_ifdata, ifdata,
1486 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
1487 }
1488 
1489 static int
1490 ipv6_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1491     uint64_t *flags)
1492 {
1493 	return (ip_getlifflags_impl(AF_INET6, phy_ifdata, ifdata,
1494 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
1495 }
1496 
1497 /*
1498  * Deliver packet up into the kernel, immitating its reception by a
1499  * network interface.
1500  */
1501 static void
1502 ip_ni_queue_in_func(void *inject)
1503 {
1504 	ip_ni_queue_func_impl(inject, B_FALSE);
1505 }
1506 
1507 /*
1508  * Deliver out of the kernel, as if it were being sent via a
1509  * raw socket so that IPFilter will see it again.
1510  */
1511 static void
1512 ip_ni_queue_out_func(void *inject)
1513 {
1514 	ip_ni_queue_func_impl(inject, B_TRUE);
1515 }
1516 
1517 /*
1518  * Shared implementation for inject via ip_output and ip_input
1519  */
1520 static void
1521 ip_ni_queue_func_impl(injection_t *inject,  boolean_t out)
1522 {
1523 	net_inject_t *packet;
1524 	conn_t *conn;
1525 	ill_t *ill;
1526 	ip_stack_t *ipst = (ip_stack_t *)inject->inj_ptr;
1527 
1528 	ASSERT(inject != NULL);
1529 	packet = &inject->inj_data;
1530 	ASSERT(packet->ni_packet != NULL);
1531 
1532 	ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical,
1533 	    B_FALSE, NULL, NULL, NULL, NULL, ipst);
1534 
1535 	/* Fallback to group names only if hook_emulation is set */
1536 	if (ill == NULL && ipst->ips_ipmp_hook_emulation) {
1537 		ill = ill_group_lookup_on_ifindex((uint_t)packet->ni_physical,
1538 		    B_FALSE, ipst);
1539 	}
1540 	if (ill == NULL) {
1541 		kmem_free(inject, sizeof (*inject));
1542 		return;
1543 	}
1544 
1545 	if (out == 0) {
1546 		if (inject->inj_isv6) {
1547 			ip_rput_v6(ill->ill_rq, packet->ni_packet);
1548 		} else {
1549 			ip_input(ill, NULL, packet->ni_packet, NULL);
1550 		}
1551 		kmem_free(inject, sizeof (*inject));
1552 		ill_refrele(ill);
1553 		return;
1554 	}
1555 
1556 	/*
1557 	 * Even though ipcl_conn_create requests that it be passed
1558 	 * a different value for "TCP", in this case there may not
1559 	 * be a TCP connection backing the packet and more than
1560 	 * likely, non-TCP packets will go here too.
1561 	 */
1562 	conn = ipcl_conn_create(IPCL_IPCCONN, KM_NOSLEEP, ipst->ips_netstack);
1563 	if (conn != NULL) {
1564 		if (inject->inj_isv6) {
1565 			conn->conn_flags |= IPCL_ISV6;
1566 			conn->conn_af_isv6 = B_TRUE;
1567 			conn->conn_src_preferences = IPV6_PREFER_SRC_DEFAULT;
1568 			conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
1569 			ip_output_v6(conn, packet->ni_packet, ill->ill_wq,
1570 			    IP_WPUT);
1571 		} else {
1572 			conn->conn_af_isv6 = B_FALSE;
1573 			conn->conn_pkt_isv6 = B_FALSE;
1574 			conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
1575 			ip_output(conn, packet->ni_packet, ill->ill_wq,
1576 			    IP_WPUT);
1577 		}
1578 
1579 		CONN_DEC_REF(conn);
1580 	}
1581 
1582 	kmem_free(inject, sizeof (*inject));
1583 	ill_refrele(ill);
1584 }
1585 
1586 /*
1587  * taskq function for nic events.
1588  */
1589 void
1590 ip_ne_queue_func(void *arg)
1591 {
1592 	hook_event_token_t hr;
1593 	hook_nic_event_int_t *info = (hook_nic_event_int_t *)arg;
1594 	ip_stack_t *ipst;
1595 	netstack_t *ns;
1596 
1597 	ns = netstack_find_by_stackid(info->hnei_stackid);
1598 	if (ns == NULL)
1599 		goto done;
1600 
1601 	ipst = ns->netstack_ip;
1602 	if (ipst == NULL)
1603 		goto done;
1604 
1605 	hr = (info->hnei_event.hne_protocol == ipst->ips_ipv6_net_data) ?
1606 	    ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
1607 	(void) hook_run(info->hnei_event.hne_protocol->netd_hooks, hr,
1608 	    (hook_data_t)&info->hnei_event);
1609 
1610 done:
1611 	if (ns != NULL)
1612 		netstack_rele(ns);
1613 	kmem_free(info->hnei_event.hne_data, info->hnei_event.hne_datalen);
1614 	kmem_free(arg, sizeof (hook_nic_event_int_t));
1615 }
1616 
1617 /*
1618  * Temporary function to support IPMP emulation for IP Filter.
1619  * Lookup an ill based on the ifindex assigned to the group.
1620  * Skips unusable ones i.e. where any of these flags are set:
1621  * (PHYI_FAILED|PHYI_OFFLINE|PHYI_INACTIVE)
1622  */
1623 ill_t *
1624 ill_group_lookup_on_ifindex(uint_t index, boolean_t isv6, ip_stack_t *ipst)
1625 {
1626 	ill_t	*ill;
1627 	phyint_t *phyi;
1628 
1629 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
1630 	phyi = phyint_lookup_group_ifindex(index, ipst);
1631 	if (phyi != NULL) {
1632 		ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4;
1633 		if (ill != NULL) {
1634 			mutex_enter(&ill->ill_lock);
1635 			if (ILL_CAN_LOOKUP(ill)) {
1636 				ill_refhold_locked(ill);
1637 				mutex_exit(&ill->ill_lock);
1638 				rw_exit(&ipst->ips_ill_g_lock);
1639 				return (ill);
1640 			}
1641 			mutex_exit(&ill->ill_lock);
1642 		}
1643 	}
1644 	rw_exit(&ipst->ips_ill_g_lock);
1645 	return (NULL);
1646 }
1647 
1648 /*
1649  * Temporary function to support IPMP emulation for IP Filter.
1650  * Lookup an ill based on the group name.
1651  * Skips unusable ones i.e. where any of these flags are set:
1652  * (PHYI_FAILED|PHYI_OFFLINE|PHYI_INACTIVE)
1653  */
1654 ill_t *
1655 ill_group_lookup_on_name(char *name, boolean_t isv6, ip_stack_t *ipst)
1656 {
1657 	ill_t	*ill;
1658 	phyint_t *phyi;
1659 
1660 	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
1661 	phyi = phyint_lookup_group(name, B_TRUE, ipst);
1662 	if (phyi != NULL) {
1663 		ill = isv6 ? phyi->phyint_illv6: phyi->phyint_illv4;
1664 		if (ill != NULL) {
1665 			mutex_enter(&ill->ill_lock);
1666 			if (ILL_CAN_LOOKUP(ill)) {
1667 				ill_refhold_locked(ill);
1668 				mutex_exit(&ill->ill_lock);
1669 				rw_exit(&ipst->ips_ill_g_lock);
1670 				return (ill);
1671 			}
1672 			mutex_exit(&ill->ill_lock);
1673 		}
1674 	}
1675 	rw_exit(&ipst->ips_ill_g_lock);
1676 	return (NULL);
1677 }
1678