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