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