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