1381a2a9aSdr /*
2381a2a9aSdr  * CDDL HEADER START
3381a2a9aSdr  *
4381a2a9aSdr  * The contents of this file are subject to the terms of the
5381a2a9aSdr  * Common Development and Distribution License (the "License").
6381a2a9aSdr  * You may not use this file except in compliance with the License.
7381a2a9aSdr  *
8381a2a9aSdr  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9381a2a9aSdr  * or http://www.opensolaris.org/os/licensing.
10381a2a9aSdr  * See the License for the specific language governing permissions
11381a2a9aSdr  * and limitations under the License.
12381a2a9aSdr  *
13381a2a9aSdr  * When distributing Covered Code, include this CDDL HEADER in each
14381a2a9aSdr  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15381a2a9aSdr  * If applicable, add the following below this CDDL HEADER, with the
16381a2a9aSdr  * fields enclosed by brackets "[]" replaced with your own identifying
17381a2a9aSdr  * information: Portions Copyright [yyyy] [name of copyright owner]
18381a2a9aSdr  *
19381a2a9aSdr  * CDDL HEADER END
20381a2a9aSdr  */
21381a2a9aSdr /*
229e3469d3SErik Nordmark  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23381a2a9aSdr  * Use is subject to license terms.
24381a2a9aSdr  */
25381a2a9aSdr 
26381a2a9aSdr #include <sys/param.h>
27381a2a9aSdr #include <sys/types.h>
28381a2a9aSdr #include <sys/systm.h>
29381a2a9aSdr #include <sys/stream.h>
30381a2a9aSdr #include <sys/strsubr.h>
31381a2a9aSdr #include <sys/pattr.h>
32381a2a9aSdr #include <sys/dlpi.h>
33381a2a9aSdr #include <sys/atomic.h>
34381a2a9aSdr #include <sys/sunddi.h>
35381a2a9aSdr #include <sys/socket.h>
36381a2a9aSdr #include <sys/neti.h>
3710e6dadfSbrendan #include <sys/sdt.h>
387ddc9b1aSDarren Reed #include <sys/cmn_err.h>
39381a2a9aSdr 
40381a2a9aSdr #include <netinet/in.h>
41bd670b35SErik Nordmark #include <inet/ipsec_impl.h>
42381a2a9aSdr #include <inet/common.h>
43381a2a9aSdr #include <inet/mib2.h>
44381a2a9aSdr #include <inet/ip.h>
45381a2a9aSdr #include <inet/ip6.h>
46381a2a9aSdr #include <inet/ip_if.h>
47381a2a9aSdr #include <inet/ip_ire.h>
48381a2a9aSdr #include <inet/ip_impl.h>
49381a2a9aSdr #include <inet/ip_ndp.h>
50381a2a9aSdr #include <inet/ipclassifier.h>
51381a2a9aSdr #include <inet/ipp_common.h>
52381a2a9aSdr #include <inet/ip_ftable.h>
53381a2a9aSdr 
54381a2a9aSdr /*
55381a2a9aSdr  * IPv4 netinfo entry point declarations.
56381a2a9aSdr  */
577ddc9b1aSDarren Reed static int 		ip_getifname(net_handle_t, phy_if_t, char *,
587ddc9b1aSDarren Reed 			    const size_t);
597ddc9b1aSDarren Reed static int 		ip_getmtu(net_handle_t, phy_if_t, lif_if_t);
607ddc9b1aSDarren Reed static int 		ip_getpmtuenabled(net_handle_t);
617ddc9b1aSDarren Reed static int 		ip_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
627ddc9b1aSDarren Reed 			    size_t, net_ifaddr_t [], void *);
63b127ac41SPhilip Kirk static int		ip_getlifzone(net_handle_t, phy_if_t, lif_if_t,
64b127ac41SPhilip Kirk 			    zoneid_t *);
65b127ac41SPhilip Kirk static int		ip_getlifflags(net_handle_t, phy_if_t, lif_if_t,
66b127ac41SPhilip Kirk 			    uint64_t *);
677ddc9b1aSDarren Reed static phy_if_t		ip_phygetnext(net_handle_t, phy_if_t);
687ddc9b1aSDarren Reed static phy_if_t 	ip_phylookup(net_handle_t, const char *);
697ddc9b1aSDarren Reed static lif_if_t 	ip_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
707ddc9b1aSDarren Reed static int 		ip_inject(net_handle_t, inject_t, net_inject_t *);
717ddc9b1aSDarren Reed static phy_if_t 	ip_routeto(net_handle_t, struct sockaddr *,
727ddc9b1aSDarren Reed 			    struct sockaddr *);
737ddc9b1aSDarren Reed static int 		ip_ispartialchecksum(net_handle_t, mblk_t *);
747ddc9b1aSDarren Reed static int 		ip_isvalidchecksum(net_handle_t, mblk_t *);
757ddc9b1aSDarren Reed 
767ddc9b1aSDarren Reed static int 		ipv6_getifname(net_handle_t, phy_if_t, char *,
777ddc9b1aSDarren Reed 			    const size_t);
787ddc9b1aSDarren Reed static int 		ipv6_getmtu(net_handle_t, phy_if_t, lif_if_t);
797ddc9b1aSDarren Reed static int 		ipv6_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
807ddc9b1aSDarren Reed 			    size_t, net_ifaddr_t [], void *);
81b127ac41SPhilip Kirk static int		ipv6_getlifzone(net_handle_t, phy_if_t, lif_if_t,
82b127ac41SPhilip Kirk 			    zoneid_t *);
83b127ac41SPhilip Kirk static int		ipv6_getlifflags(net_handle_t, phy_if_t, lif_if_t,
84b127ac41SPhilip Kirk 			    uint64_t *);
857ddc9b1aSDarren Reed static phy_if_t 	ipv6_phygetnext(net_handle_t, phy_if_t);
867ddc9b1aSDarren Reed static phy_if_t 	ipv6_phylookup(net_handle_t, const char *);
877ddc9b1aSDarren Reed static lif_if_t 	ipv6_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
887ddc9b1aSDarren Reed static int 		ipv6_inject(net_handle_t, inject_t, net_inject_t *);
897ddc9b1aSDarren Reed static phy_if_t 	ipv6_routeto(net_handle_t, struct sockaddr *,
907ddc9b1aSDarren Reed 			    struct sockaddr *);
917ddc9b1aSDarren Reed static int 		ipv6_isvalidchecksum(net_handle_t, mblk_t *);
92381a2a9aSdr 
93bd670b35SErik Nordmark static int 		net_no_getmtu(net_handle_t, phy_if_t, lif_if_t);
94bd670b35SErik Nordmark static int 		net_no_getpmtuenabled(net_handle_t);
95bd670b35SErik Nordmark static lif_if_t 	net_no_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
96bd670b35SErik Nordmark static int 		net_no_inject(net_handle_t, inject_t, net_inject_t *);
97bd670b35SErik Nordmark static phy_if_t 	net_no_routeto(net_handle_t, struct sockaddr *,
98bd670b35SErik Nordmark 			    struct sockaddr *);
99bd670b35SErik Nordmark static int 		net_no_ispartialchecksum(net_handle_t, mblk_t *);
100bd670b35SErik Nordmark static int 		net_no_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
101bd670b35SErik Nordmark 			    size_t, net_ifaddr_t [], void *);
102bd670b35SErik Nordmark static int		net_no_getlifzone(net_handle_t, phy_if_t, lif_if_t,
103bd670b35SErik Nordmark 			    zoneid_t *);
104bd670b35SErik Nordmark static int		net_no_getlifflags(net_handle_t, phy_if_t, lif_if_t,
105bd670b35SErik Nordmark 			    uint64_t *);
106bd670b35SErik Nordmark 
107381a2a9aSdr /* Netinfo private functions */
108381a2a9aSdr static	int		ip_getifname_impl(phy_if_t, char *,
1097ddc9b1aSDarren Reed 			    const size_t, boolean_t, ip_stack_t *);
110f4b3ec61Sdh static	int		ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t,
1117ddc9b1aSDarren Reed 			    ip_stack_t *);
112f4b3ec61Sdh static	phy_if_t	ip_phylookup_impl(const char *, boolean_t,
1137ddc9b1aSDarren Reed 			    ip_stack_t *);
114f4b3ec61Sdh static	lif_if_t	ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t,
1157ddc9b1aSDarren Reed 			    ip_stack_t *);
116f4b3ec61Sdh static	int		ip_inject_impl(inject_t, net_inject_t *, boolean_t,
1177ddc9b1aSDarren Reed 			    ip_stack_t *);
118381a2a9aSdr static	int		ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t,
119381a2a9aSdr 			    void *);
1207ddc9b1aSDarren Reed static	phy_if_t	ip_routeto_impl(struct sockaddr *, struct sockaddr *,
1217ddc9b1aSDarren Reed 			    ip_stack_t *);
122381a2a9aSdr static	int		ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t,
123f4b3ec61Sdh 			    size_t, net_ifaddr_t [], struct sockaddr *,
124f4b3ec61Sdh 			    ip_stack_t *);
125381a2a9aSdr static	void		ip_ni_queue_in_func(void *);
126381a2a9aSdr static	void		ip_ni_queue_out_func(void *);
127381a2a9aSdr static	void		ip_ni_queue_func_impl(injection_t *,  boolean_t);
128381a2a9aSdr 
1297ddc9b1aSDarren Reed static net_protocol_t ipv4info = {
130381a2a9aSdr 	NETINFO_VERSION,
131381a2a9aSdr 	NHF_INET,
132381a2a9aSdr 	ip_getifname,
133381a2a9aSdr 	ip_getmtu,
134381a2a9aSdr 	ip_getpmtuenabled,
135381a2a9aSdr 	ip_getlifaddr,
136b127ac41SPhilip Kirk 	ip_getlifzone,
137b127ac41SPhilip Kirk 	ip_getlifflags,
138381a2a9aSdr 	ip_phygetnext,
139381a2a9aSdr 	ip_phylookup,
140381a2a9aSdr 	ip_lifgetnext,
141381a2a9aSdr 	ip_inject,
142381a2a9aSdr 	ip_routeto,
143381a2a9aSdr 	ip_ispartialchecksum,
144381a2a9aSdr 	ip_isvalidchecksum
145381a2a9aSdr };
146381a2a9aSdr 
147381a2a9aSdr 
1487ddc9b1aSDarren Reed static net_protocol_t ipv6info = {
149381a2a9aSdr 	NETINFO_VERSION,
150381a2a9aSdr 	NHF_INET6,
151381a2a9aSdr 	ipv6_getifname,
152381a2a9aSdr 	ipv6_getmtu,
153381a2a9aSdr 	ip_getpmtuenabled,
154381a2a9aSdr 	ipv6_getlifaddr,
155b127ac41SPhilip Kirk 	ipv6_getlifzone,
156b127ac41SPhilip Kirk 	ipv6_getlifflags,
157381a2a9aSdr 	ipv6_phygetnext,
158381a2a9aSdr 	ipv6_phylookup,
159381a2a9aSdr 	ipv6_lifgetnext,
160381a2a9aSdr 	ipv6_inject,
161381a2a9aSdr 	ipv6_routeto,
162381a2a9aSdr 	ip_ispartialchecksum,
163381a2a9aSdr 	ipv6_isvalidchecksum
164381a2a9aSdr };
165381a2a9aSdr 
166bd670b35SErik Nordmark static net_protocol_t arp_netinfo = {
167bd670b35SErik Nordmark 	NETINFO_VERSION,
168bd670b35SErik Nordmark 	NHF_ARP,
169bd670b35SErik Nordmark 	ip_getifname,
170bd670b35SErik Nordmark 	net_no_getmtu,
171bd670b35SErik Nordmark 	net_no_getpmtuenabled,
172bd670b35SErik Nordmark 	net_no_getlifaddr,
173bd670b35SErik Nordmark 	net_no_getlifzone,
174bd670b35SErik Nordmark 	net_no_getlifflags,
175bd670b35SErik Nordmark 	ip_phygetnext,
176bd670b35SErik Nordmark 	ip_phylookup,
177bd670b35SErik Nordmark 	net_no_lifgetnext,
178bd670b35SErik Nordmark 	net_no_inject,
179bd670b35SErik Nordmark 	net_no_routeto,
180bd670b35SErik Nordmark 	net_no_ispartialchecksum,
181bd670b35SErik Nordmark 	ip_isvalidchecksum
182bd670b35SErik Nordmark };
183bd670b35SErik Nordmark 
184381a2a9aSdr /*
185381a2a9aSdr  * The taskq eventq_queue_in is used to process the upside inject messages.
186381a2a9aSdr  * The taskq eventq_queue_out is used to process the downside inject messages.
187381a2a9aSdr  * The taskq eventq_queue_nic is used to process the nic event messages.
188381a2a9aSdr  */
189381a2a9aSdr static ddi_taskq_t 	*eventq_queue_in = NULL;
190381a2a9aSdr static ddi_taskq_t 	*eventq_queue_out = NULL;
191381a2a9aSdr ddi_taskq_t 	*eventq_queue_nic = NULL;
192381a2a9aSdr 
193381a2a9aSdr /*
194f4b3ec61Sdh  * Initialize queues for inject.
195381a2a9aSdr  */
196381a2a9aSdr void
ip_net_g_init()197f4b3ec61Sdh ip_net_g_init()
198381a2a9aSdr {
199381a2a9aSdr 	if (eventq_queue_out == NULL) {
200381a2a9aSdr 		eventq_queue_out = ddi_taskq_create(NULL,
201381a2a9aSdr 		    "IP_INJECT_QUEUE_OUT", 1, TASKQ_DEFAULTPRI, 0);
202381a2a9aSdr 
203381a2a9aSdr 		if (eventq_queue_out == NULL)
204381a2a9aSdr 			cmn_err(CE_NOTE, "ipv4_net_init: "
205381a2a9aSdr 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_OUT");
206381a2a9aSdr 	}
207381a2a9aSdr 
208381a2a9aSdr 	if (eventq_queue_in == NULL) {
209381a2a9aSdr 		eventq_queue_in = ddi_taskq_create(NULL,
210381a2a9aSdr 		    "IP_INJECT_QUEUE_IN", 1, TASKQ_DEFAULTPRI, 0);
211381a2a9aSdr 
212381a2a9aSdr 		if (eventq_queue_in == NULL)
213381a2a9aSdr 			cmn_err(CE_NOTE, "ipv4_net_init: "
214381a2a9aSdr 			    "ddi_taskq_create failed for IP_INJECT_QUEUE_IN");
215381a2a9aSdr 	}
216381a2a9aSdr 
217381a2a9aSdr 	if (eventq_queue_nic == NULL) {
218381a2a9aSdr 		eventq_queue_nic = ddi_taskq_create(NULL,
219381a2a9aSdr 		    "IP_NIC_EVENT_QUEUE", 1, TASKQ_DEFAULTPRI, 0);
220381a2a9aSdr 
221381a2a9aSdr 		if (eventq_queue_nic == NULL)
222381a2a9aSdr 			cmn_err(CE_NOTE, "ipv4_net_init: "
223381a2a9aSdr 			    "ddi_taskq_create failed for IP_NIC_EVENT_QUEUE");
224381a2a9aSdr 	}
225381a2a9aSdr }
226381a2a9aSdr 
227381a2a9aSdr /*
228f4b3ec61Sdh  * Destroy inject queues
229381a2a9aSdr  */
230381a2a9aSdr void
ip_net_g_destroy()231f4b3ec61Sdh ip_net_g_destroy()
232381a2a9aSdr {
233381a2a9aSdr 	if (eventq_queue_nic != NULL) {
234381a2a9aSdr 		ddi_taskq_destroy(eventq_queue_nic);
235381a2a9aSdr 		eventq_queue_nic = NULL;
236381a2a9aSdr 	}
237381a2a9aSdr 
238381a2a9aSdr 	if (eventq_queue_in != NULL) {
239381a2a9aSdr 		ddi_taskq_destroy(eventq_queue_in);
240381a2a9aSdr 		eventq_queue_in = NULL;
241381a2a9aSdr 	}
242381a2a9aSdr 
243381a2a9aSdr 	if (eventq_queue_out != NULL) {
244381a2a9aSdr 		ddi_taskq_destroy(eventq_queue_out);
245381a2a9aSdr 		eventq_queue_out = NULL;
246381a2a9aSdr 	}
247f4b3ec61Sdh }
248f4b3ec61Sdh 
249f4b3ec61Sdh /*
250f4b3ec61Sdh  * Register IPv4 and IPv6 netinfo functions and initialize queues for inject.
251f4b3ec61Sdh  */
252f4b3ec61Sdh void
ip_net_init(ip_stack_t * ipst,netstack_t * ns)253f4b3ec61Sdh ip_net_init(ip_stack_t *ipst, netstack_t *ns)
254f4b3ec61Sdh {
2557ddc9b1aSDarren Reed 	netid_t id;
2567ddc9b1aSDarren Reed 
2577ddc9b1aSDarren Reed 	id = net_getnetidbynetstackid(ns->netstack_stackid);
2587ddc9b1aSDarren Reed 	ASSERT(id != -1);
259f4b3ec61Sdh 
2607ddc9b1aSDarren Reed 	ipst->ips_ipv4_net_data = net_protocol_register(id, &ipv4info);
261f4b3ec61Sdh 	ASSERT(ipst->ips_ipv4_net_data != NULL);
262f4b3ec61Sdh 
2637ddc9b1aSDarren Reed 	ipst->ips_ipv6_net_data = net_protocol_register(id, &ipv6info);
264f4b3ec61Sdh 	ASSERT(ipst->ips_ipv6_net_data != NULL);
265bd670b35SErik Nordmark 
266bd670b35SErik Nordmark 	ipst->ips_arp_net_data = net_protocol_register(id, &arp_netinfo);
267bd670b35SErik Nordmark 	ASSERT(ipst->ips_ipv6_net_data != NULL);
268f4b3ec61Sdh }
269f4b3ec61Sdh 
270381a2a9aSdr 
271f4b3ec61Sdh /*
2728ad74188SDarren Reed  * Unregister IPv4 and IPv6 functions.
273f4b3ec61Sdh  */
274f4b3ec61Sdh void
ip_net_destroy(ip_stack_t * ipst)275f4b3ec61Sdh ip_net_destroy(ip_stack_t *ipst)
276f4b3ec61Sdh {
277f4b3ec61Sdh 	if (ipst->ips_ipv4_net_data != NULL) {
2787ddc9b1aSDarren Reed 		if (net_protocol_unregister(ipst->ips_ipv4_net_data) == 0)
279f4b3ec61Sdh 			ipst->ips_ipv4_net_data = NULL;
280381a2a9aSdr 	}
281381a2a9aSdr 
282f4b3ec61Sdh 	if (ipst->ips_ipv6_net_data != NULL) {
2837ddc9b1aSDarren Reed 		if (net_protocol_unregister(ipst->ips_ipv6_net_data) == 0)
284f4b3ec61Sdh 			ipst->ips_ipv6_net_data = NULL;
285381a2a9aSdr 	}
286bd670b35SErik Nordmark 
287bd670b35SErik Nordmark 	if (ipst->ips_arp_net_data != NULL) {
288bd670b35SErik Nordmark 		if (net_protocol_unregister(ipst->ips_arp_net_data) == 0)
289bd670b35SErik Nordmark 			ipst->ips_arp_net_data = NULL;
290bd670b35SErik Nordmark 	}
291381a2a9aSdr }
292381a2a9aSdr 
293381a2a9aSdr /*
294381a2a9aSdr  * Initialize IPv4 hooks family the event
295381a2a9aSdr  */
296381a2a9aSdr void
ipv4_hook_init(ip_stack_t * ipst)297f4b3ec61Sdh ipv4_hook_init(ip_stack_t *ipst)
298381a2a9aSdr {
299f4b3ec61Sdh 	HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4);
3007ddc9b1aSDarren Reed 	if (net_family_register(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root)
301f4b3ec61Sdh 	    != 0) {
302381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3037ddc9b1aSDarren Reed 		    "net_family_register failed for ipv4");
304381a2a9aSdr 	}
305381a2a9aSdr 
306f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN);
3077ddc9b1aSDarren Reed 	ipst->ips_ipv4firewall_physical_in = net_event_register(
308f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event);
309f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_physical_in == NULL) {
310381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3117ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/physical_in");
312381a2a9aSdr 	}
313381a2a9aSdr 
314f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT);
3157ddc9b1aSDarren Reed 	ipst->ips_ipv4firewall_physical_out = net_event_register(
316f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event);
317f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_physical_out == NULL) {
318381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3197ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/physical_out");
320381a2a9aSdr 	}
321381a2a9aSdr 
322f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING);
3237ddc9b1aSDarren Reed 	ipst->ips_ipv4firewall_forwarding = net_event_register(
324f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event);
325f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_forwarding == NULL) {
326381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3277ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/forwarding");
328381a2a9aSdr 	}
329381a2a9aSdr 
330f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN);
3317ddc9b1aSDarren Reed 	ipst->ips_ipv4firewall_loopback_in = net_event_register(
332f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event);
333f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_loopback_in == NULL) {
334381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3357ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/loopback_in");
336381a2a9aSdr 	}
337381a2a9aSdr 
338f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT);
3397ddc9b1aSDarren Reed 	ipst->ips_ipv4firewall_loopback_out = net_event_register(
340f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event);
341f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_loopback_out == NULL) {
342381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3437ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/loopback_out");
344381a2a9aSdr 	}
345381a2a9aSdr 
346f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS);
347f4b3ec61Sdh 	ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY;
3487ddc9b1aSDarren Reed 	ipst->ips_ipv4nicevents = net_event_register(
349f4b3ec61Sdh 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events);
350f4b3ec61Sdh 	if (ipst->ips_ipv4nicevents == NULL) {
351381a2a9aSdr 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3527ddc9b1aSDarren Reed 		    "net_event_register failed for ipv4/nic_events");
353381a2a9aSdr 	}
3540a0e9771SDarren Reed 
3550a0e9771SDarren Reed 	HOOK_EVENT_INIT(&ipst->ips_ip4_observe, NH_OBSERVE);
3560a0e9771SDarren Reed 	ipst->ips_ip4_observe.he_flags = HOOK_RDONLY;
3570a0e9771SDarren Reed 	ipst->ips_ipv4observing = net_event_register(
3580a0e9771SDarren Reed 	    ipst->ips_ipv4_net_data, &ipst->ips_ip4_observe);
3590a0e9771SDarren Reed 	if (ipst->ips_ipv4observing == NULL) {
3600a0e9771SDarren Reed 		cmn_err(CE_NOTE, "ipv4_hook_init: "
3610a0e9771SDarren Reed 		    "net_event_register failed for ipv4/observe");
3620a0e9771SDarren Reed 	}
3630a0e9771SDarren Reed 
364381a2a9aSdr }
365381a2a9aSdr 
3668ad74188SDarren Reed void
ipv4_hook_shutdown(ip_stack_t * ipst)3678ad74188SDarren Reed ipv4_hook_shutdown(ip_stack_t *ipst)
3688ad74188SDarren Reed {
3698ad74188SDarren Reed 	if (ipst->ips_ipv4firewall_forwarding != NULL) {
3708ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3718ad74188SDarren Reed 		    &ipst->ips_ip4_forwarding_event);
3728ad74188SDarren Reed 	}
3738ad74188SDarren Reed 
3748ad74188SDarren Reed 	if (ipst->ips_ipv4firewall_physical_in != NULL) {
3758ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3768ad74188SDarren Reed 		    &ipst->ips_ip4_physical_in_event);
3778ad74188SDarren Reed 	}
3788ad74188SDarren Reed 
3798ad74188SDarren Reed 	if (ipst->ips_ipv4firewall_physical_out != NULL) {
3808ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3818ad74188SDarren Reed 		    &ipst->ips_ip4_physical_out_event);
3828ad74188SDarren Reed 	}
3838ad74188SDarren Reed 
3848ad74188SDarren Reed 	if (ipst->ips_ipv4firewall_loopback_in != NULL) {
3858ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3868ad74188SDarren Reed 		    &ipst->ips_ip4_loopback_in_event);
3878ad74188SDarren Reed 	}
3888ad74188SDarren Reed 
3898ad74188SDarren Reed 	if (ipst->ips_ipv4firewall_loopback_out != NULL) {
3908ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3918ad74188SDarren Reed 		    &ipst->ips_ip4_loopback_out_event);
3928ad74188SDarren Reed 	}
3938ad74188SDarren Reed 
3948ad74188SDarren Reed 	if (ipst->ips_ipv4nicevents != NULL) {
3958ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
3968ad74188SDarren Reed 		    &ipst->ips_ip4_nic_events);
3978ad74188SDarren Reed 	}
3988ad74188SDarren Reed 
3990a0e9771SDarren Reed 	if (ipst->ips_ipv4observing != NULL) {
4000a0e9771SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv4_net_data,
4010a0e9771SDarren Reed 		    &ipst->ips_ip4_observe);
4020a0e9771SDarren Reed 	}
4030a0e9771SDarren Reed 
4048ad74188SDarren Reed 	(void) net_family_shutdown(ipst->ips_ipv4_net_data,
4058ad74188SDarren Reed 	    &ipst->ips_ipv4root);
4068ad74188SDarren Reed }
4078ad74188SDarren Reed 
408381a2a9aSdr void
ipv4_hook_destroy(ip_stack_t * ipst)409f4b3ec61Sdh ipv4_hook_destroy(ip_stack_t *ipst)
410381a2a9aSdr {
411f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_forwarding != NULL) {
4127ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
413f4b3ec61Sdh 		    &ipst->ips_ip4_forwarding_event) == 0)
414f4b3ec61Sdh 			ipst->ips_ipv4firewall_forwarding = NULL;
415381a2a9aSdr 	}
416381a2a9aSdr 
417f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_physical_in != NULL) {
4187ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
419f4b3ec61Sdh 		    &ipst->ips_ip4_physical_in_event) == 0)
420f4b3ec61Sdh 			ipst->ips_ipv4firewall_physical_in = NULL;
421381a2a9aSdr 	}
422381a2a9aSdr 
423f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_physical_out != NULL) {
4247ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
425f4b3ec61Sdh 		    &ipst->ips_ip4_physical_out_event) == 0)
426f4b3ec61Sdh 			ipst->ips_ipv4firewall_physical_out = NULL;
427381a2a9aSdr 	}
428381a2a9aSdr 
429f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_loopback_in != NULL) {
4307ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
431f4b3ec61Sdh 		    &ipst->ips_ip4_loopback_in_event) == 0)
432f4b3ec61Sdh 			ipst->ips_ipv4firewall_loopback_in = NULL;
433381a2a9aSdr 	}
434381a2a9aSdr 
435f4b3ec61Sdh 	if (ipst->ips_ipv4firewall_loopback_out != NULL) {
4367ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
437f4b3ec61Sdh 		    &ipst->ips_ip4_loopback_out_event) == 0)
438f4b3ec61Sdh 			ipst->ips_ipv4firewall_loopback_out = NULL;
439381a2a9aSdr 	}
440381a2a9aSdr 
441f4b3ec61Sdh 	if (ipst->ips_ipv4nicevents != NULL) {
4427ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
443f4b3ec61Sdh 		    &ipst->ips_ip4_nic_events) == 0)
444f4b3ec61Sdh 			ipst->ips_ipv4nicevents = NULL;
445381a2a9aSdr 	}
446381a2a9aSdr 
4470a0e9771SDarren Reed 	if (ipst->ips_ipv4observing != NULL) {
4480a0e9771SDarren Reed 		if (net_event_unregister(ipst->ips_ipv4_net_data,
4490a0e9771SDarren Reed 		    &ipst->ips_ip4_observe) == 0)
4500a0e9771SDarren Reed 			ipst->ips_ipv4observing = NULL;
4510a0e9771SDarren Reed 	}
4520a0e9771SDarren Reed 
4537ddc9b1aSDarren Reed 	(void) net_family_unregister(ipst->ips_ipv4_net_data,
454f4b3ec61Sdh 	    &ipst->ips_ipv4root);
455381a2a9aSdr }
456381a2a9aSdr 
457381a2a9aSdr /*
458381a2a9aSdr  * Initialize IPv6 hooks family and event
459381a2a9aSdr  */
460381a2a9aSdr void
ipv6_hook_init(ip_stack_t * ipst)461f4b3ec61Sdh ipv6_hook_init(ip_stack_t *ipst)
462381a2a9aSdr {
463381a2a9aSdr 
464f4b3ec61Sdh 	HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6);
4657ddc9b1aSDarren Reed 	if (net_family_register(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root)
466f4b3ec61Sdh 	    != 0) {
467381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
4687ddc9b1aSDarren Reed 		    "net_family_register failed for ipv6");
469381a2a9aSdr 	}
470381a2a9aSdr 
471f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN);
4727ddc9b1aSDarren Reed 	ipst->ips_ipv6firewall_physical_in = net_event_register(
473f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event);
474f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_physical_in == NULL) {
475381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
4767ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/physical_in");
477381a2a9aSdr 	}
478381a2a9aSdr 
479f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT);
4807ddc9b1aSDarren Reed 	ipst->ips_ipv6firewall_physical_out = net_event_register(
481f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event);
482f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_physical_out == NULL) {
483381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
4847ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/physical_out");
485381a2a9aSdr 	}
486381a2a9aSdr 
487f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING);
4887ddc9b1aSDarren Reed 	ipst->ips_ipv6firewall_forwarding = net_event_register(
489f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event);
490f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_forwarding == NULL) {
491381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
4927ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/forwarding");
493381a2a9aSdr 	}
494381a2a9aSdr 
495f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN);
4967ddc9b1aSDarren Reed 	ipst->ips_ipv6firewall_loopback_in = net_event_register(
497f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event);
498f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_loopback_in == NULL) {
499381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
5007ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/loopback_in");
501381a2a9aSdr 	}
502381a2a9aSdr 
503f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT);
5047ddc9b1aSDarren Reed 	ipst->ips_ipv6firewall_loopback_out = net_event_register(
505f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event);
506f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_loopback_out == NULL) {
507381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
5087ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/loopback_out");
509381a2a9aSdr 	}
510381a2a9aSdr 
511f4b3ec61Sdh 	HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS);
512f4b3ec61Sdh 	ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY;
5137ddc9b1aSDarren Reed 	ipst->ips_ipv6nicevents = net_event_register(
514f4b3ec61Sdh 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events);
515f4b3ec61Sdh 	if (ipst->ips_ipv6nicevents == NULL) {
516381a2a9aSdr 		cmn_err(CE_NOTE, "ipv6_hook_init: "
5177ddc9b1aSDarren Reed 		    "net_event_register failed for ipv6/nic_events");
518381a2a9aSdr 	}
5190a0e9771SDarren Reed 
5200a0e9771SDarren Reed 	HOOK_EVENT_INIT(&ipst->ips_ip6_observe, NH_OBSERVE);
5210a0e9771SDarren Reed 	ipst->ips_ip6_observe.he_flags = HOOK_RDONLY;
5220a0e9771SDarren Reed 	ipst->ips_ipv6observing = net_event_register(
5230a0e9771SDarren Reed 	    ipst->ips_ipv6_net_data, &ipst->ips_ip6_observe);
5240a0e9771SDarren Reed 	if (ipst->ips_ipv6observing == NULL) {
5250a0e9771SDarren Reed 		cmn_err(CE_NOTE, "ipv6_hook_init: "
5260a0e9771SDarren Reed 		    "net_event_register failed for ipv6/observe");
5270a0e9771SDarren Reed 	}
528381a2a9aSdr }
529381a2a9aSdr 
5308ad74188SDarren Reed void
ipv6_hook_shutdown(ip_stack_t * ipst)5318ad74188SDarren Reed ipv6_hook_shutdown(ip_stack_t *ipst)
5328ad74188SDarren Reed {
5338ad74188SDarren Reed 	if (ipst->ips_ipv6firewall_forwarding != NULL) {
5348ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5358ad74188SDarren Reed 		    &ipst->ips_ip6_forwarding_event);
5368ad74188SDarren Reed 	}
5378ad74188SDarren Reed 
5388ad74188SDarren Reed 	if (ipst->ips_ipv6firewall_physical_in != NULL) {
5398ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5408ad74188SDarren Reed 		    &ipst->ips_ip6_physical_in_event);
5418ad74188SDarren Reed 	}
5428ad74188SDarren Reed 
5438ad74188SDarren Reed 	if (ipst->ips_ipv6firewall_physical_out != NULL) {
5448ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5458ad74188SDarren Reed 		    &ipst->ips_ip6_physical_out_event);
5468ad74188SDarren Reed 	}
5478ad74188SDarren Reed 
5488ad74188SDarren Reed 	if (ipst->ips_ipv6firewall_loopback_in != NULL) {
5498ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5508ad74188SDarren Reed 		    &ipst->ips_ip6_loopback_in_event);
5518ad74188SDarren Reed 	}
5528ad74188SDarren Reed 
5538ad74188SDarren Reed 	if (ipst->ips_ipv6firewall_loopback_out != NULL) {
5548ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5558ad74188SDarren Reed 		    &ipst->ips_ip6_loopback_out_event);
5568ad74188SDarren Reed 	}
5578ad74188SDarren Reed 
5588ad74188SDarren Reed 	if (ipst->ips_ipv6nicevents != NULL) {
5598ad74188SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5608ad74188SDarren Reed 		    &ipst->ips_ip6_nic_events);
5618ad74188SDarren Reed 	}
5628ad74188SDarren Reed 
5630a0e9771SDarren Reed 	if (ipst->ips_ipv6observing != NULL) {
5640a0e9771SDarren Reed 		(void) net_event_shutdown(ipst->ips_ipv6_net_data,
5650a0e9771SDarren Reed 		    &ipst->ips_ip6_observe);
5660a0e9771SDarren Reed 	}
5670a0e9771SDarren Reed 
5688ad74188SDarren Reed 	(void) net_family_shutdown(ipst->ips_ipv6_net_data,
5698ad74188SDarren Reed 	    &ipst->ips_ipv6root);
5708ad74188SDarren Reed }
5718ad74188SDarren Reed 
572381a2a9aSdr void
ipv6_hook_destroy(ip_stack_t * ipst)573f4b3ec61Sdh ipv6_hook_destroy(ip_stack_t *ipst)
574381a2a9aSdr {
575f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_forwarding != NULL) {
5767ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
577f4b3ec61Sdh 		    &ipst->ips_ip6_forwarding_event) == 0)
578f4b3ec61Sdh 			ipst->ips_ipv6firewall_forwarding = NULL;
579381a2a9aSdr 	}
580381a2a9aSdr 
581f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_physical_in != NULL) {
5827ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
583f4b3ec61Sdh 		    &ipst->ips_ip6_physical_in_event) == 0)
584f4b3ec61Sdh 			ipst->ips_ipv6firewall_physical_in = NULL;
585381a2a9aSdr 	}
586381a2a9aSdr 
587f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_physical_out != NULL) {
5887ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
589f4b3ec61Sdh 		    &ipst->ips_ip6_physical_out_event) == 0)
590f4b3ec61Sdh 			ipst->ips_ipv6firewall_physical_out = NULL;
591381a2a9aSdr 	}
592381a2a9aSdr 
593f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_loopback_in != NULL) {
5947ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
595f4b3ec61Sdh 		    &ipst->ips_ip6_loopback_in_event) == 0)
596f4b3ec61Sdh 			ipst->ips_ipv6firewall_loopback_in = NULL;
597381a2a9aSdr 	}
598381a2a9aSdr 
599f4b3ec61Sdh 	if (ipst->ips_ipv6firewall_loopback_out != NULL) {
6007ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
601f4b3ec61Sdh 		    &ipst->ips_ip6_loopback_out_event) == 0)
602f4b3ec61Sdh 			ipst->ips_ipv6firewall_loopback_out = NULL;
603381a2a9aSdr 	}
604381a2a9aSdr 
605f4b3ec61Sdh 	if (ipst->ips_ipv6nicevents != NULL) {
6067ddc9b1aSDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
607f4b3ec61Sdh 		    &ipst->ips_ip6_nic_events) == 0)
608f4b3ec61Sdh 			ipst->ips_ipv6nicevents = NULL;
609381a2a9aSdr 	}
610381a2a9aSdr 
6110a0e9771SDarren Reed 	if (ipst->ips_ipv6observing != NULL) {
6120a0e9771SDarren Reed 		if (net_event_unregister(ipst->ips_ipv6_net_data,
6130a0e9771SDarren Reed 		    &ipst->ips_ip6_observe) == 0)
6140a0e9771SDarren Reed 			ipst->ips_ipv6observing = NULL;
6150a0e9771SDarren Reed 	}
6160a0e9771SDarren Reed 
6177ddc9b1aSDarren Reed 	(void) net_family_unregister(ipst->ips_ipv6_net_data,
618f4b3ec61Sdh 	    &ipst->ips_ipv6root);
619381a2a9aSdr }
620381a2a9aSdr 
621381a2a9aSdr /*
622381a2a9aSdr  * Determine the name of an IPv4 interface
623381a2a9aSdr  */
624381a2a9aSdr static int
ip_getifname(net_handle_t neti,phy_if_t phy_ifdata,char * buffer,const size_t buflen)6257ddc9b1aSDarren Reed ip_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
6267ddc9b1aSDarren Reed     const size_t buflen)
627381a2a9aSdr {
628f4b3ec61Sdh 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE,
6297ddc9b1aSDarren Reed 	    neti->netd_stack->nts_netstack->netstack_ip));
630381a2a9aSdr }
631381a2a9aSdr 
632381a2a9aSdr /*
633381a2a9aSdr  * Determine the name of an IPv6 interface
634381a2a9aSdr  */
635381a2a9aSdr static int
ipv6_getifname(net_handle_t neti,phy_if_t phy_ifdata,char * buffer,const size_t buflen)6367ddc9b1aSDarren Reed ipv6_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
6377ddc9b1aSDarren Reed     const size_t buflen)
638381a2a9aSdr {
639f4b3ec61Sdh 	return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE,
6407ddc9b1aSDarren Reed 	    neti->netd_stack->nts_netstack->netstack_ip));
641381a2a9aSdr }
642381a2a9aSdr 
643381a2a9aSdr /*
644381a2a9aSdr  * Shared implementation to determine the name of a given network interface
645381a2a9aSdr  */
646381a2a9aSdr /* ARGSUSED */
647381a2a9aSdr static int
ip_getifname_impl(phy_if_t phy_ifdata,char * buffer,const size_t buflen,boolean_t isv6,ip_stack_t * ipst)648381a2a9aSdr ip_getifname_impl(phy_if_t phy_ifdata,
649f4b3ec61Sdh     char *buffer, const size_t buflen, boolean_t isv6, ip_stack_t *ipst)
650381a2a9aSdr {
651381a2a9aSdr 	ill_t *ill;
652381a2a9aSdr 
653381a2a9aSdr 	ASSERT(buffer != NULL);
654381a2a9aSdr 
655bd670b35SErik Nordmark 	ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, ipst);
656e11c3f44Smeem 	if (ill == NULL)
657381a2a9aSdr 		return (1);
658381a2a9aSdr 
659e11c3f44Smeem 	(void) strlcpy(buffer, ill->ill_name, buflen);
660e11c3f44Smeem 	ill_refrele(ill);
661e11c3f44Smeem 	return (0);
662381a2a9aSdr }
663381a2a9aSdr 
664381a2a9aSdr /*
665381a2a9aSdr  * Determine the MTU of an IPv4 network interface
666381a2a9aSdr  */
667381a2a9aSdr static int
ip_getmtu(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata)6687ddc9b1aSDarren Reed ip_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
669381a2a9aSdr {
6707ddc9b1aSDarren Reed 	netstack_t *ns;
6717ddc9b1aSDarren Reed 
6727ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
673f4b3ec61Sdh 	ASSERT(ns != NULL);
674f4b3ec61Sdh 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip));
675381a2a9aSdr }
676381a2a9aSdr 
677381a2a9aSdr /*
678381a2a9aSdr  * Determine the MTU of an IPv6 network interface
679381a2a9aSdr  */
680381a2a9aSdr static int
ipv6_getmtu(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata)6817ddc9b1aSDarren Reed ipv6_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
682381a2a9aSdr {
6837ddc9b1aSDarren Reed 	netstack_t *ns;
6847ddc9b1aSDarren Reed 
6857ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
686f4b3ec61Sdh 	ASSERT(ns != NULL);
687f4b3ec61Sdh 	return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip));
688381a2a9aSdr }
689381a2a9aSdr 
690381a2a9aSdr /*
691381a2a9aSdr  * Shared implementation to determine the MTU of a network interface
692381a2a9aSdr  */
693381a2a9aSdr /* ARGSUSED */
694381a2a9aSdr static int
ip_getmtu_impl(phy_if_t phy_ifdata,lif_if_t ifdata,boolean_t isv6,ip_stack_t * ipst)695f4b3ec61Sdh ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
696f4b3ec61Sdh     ip_stack_t *ipst)
697381a2a9aSdr {
698381a2a9aSdr 	lif_if_t ipifid;
699381a2a9aSdr 	ipif_t *ipif;
700381a2a9aSdr 	int mtu;
701381a2a9aSdr 
702381a2a9aSdr 	ipifid = UNMAP_IPIF_ID(ifdata);
703381a2a9aSdr 
704f4b3ec61Sdh 	ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid,
705f4b3ec61Sdh 	    isv6, ipst);
706381a2a9aSdr 	if (ipif == NULL)
707381a2a9aSdr 		return (0);
708381a2a9aSdr 
709bd670b35SErik Nordmark 	mtu = ipif->ipif_ill->ill_mtu;
710381a2a9aSdr 	ipif_refrele(ipif);
711381a2a9aSdr 
712381a2a9aSdr 	if (mtu == 0) {
713381a2a9aSdr 		ill_t *ill;
714381a2a9aSdr 
715381a2a9aSdr 		if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6,
716bd670b35SErik Nordmark 		    ipst)) == NULL) {
717e11c3f44Smeem 			return (0);
718381a2a9aSdr 		}
719bd670b35SErik Nordmark 		mtu = ill->ill_mtu;
720381a2a9aSdr 		ill_refrele(ill);
721381a2a9aSdr 	}
722381a2a9aSdr 
723381a2a9aSdr 	return (mtu);
724381a2a9aSdr }
725381a2a9aSdr 
726381a2a9aSdr /*
727381a2a9aSdr  * Determine if path MTU discovery is enabled for IP
728381a2a9aSdr  */
729381a2a9aSdr static int
ip_getpmtuenabled(net_handle_t neti)7307ddc9b1aSDarren Reed ip_getpmtuenabled(net_handle_t neti)
731381a2a9aSdr {
7327ddc9b1aSDarren Reed 	netstack_t *ns;
7337ddc9b1aSDarren Reed 
7347ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
735f4b3ec61Sdh 	ASSERT(ns != NULL);
7367ddc9b1aSDarren Reed 	return (ns->netstack_ip->ips_ip_path_mtu_discovery);
737381a2a9aSdr }
738381a2a9aSdr 
739381a2a9aSdr /*
740381a2a9aSdr  * Get next interface from the current list of IPv4 physical network interfaces
741381a2a9aSdr  */
742381a2a9aSdr static phy_if_t
ip_phygetnext(net_handle_t neti,phy_if_t phy_ifdata)7437ddc9b1aSDarren Reed ip_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
744381a2a9aSdr {
7457ddc9b1aSDarren Reed 	netstack_t *ns;
7467ddc9b1aSDarren Reed 
7477ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
748f4b3ec61Sdh 	ASSERT(ns != NULL);
749f4b3ec61Sdh 	return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip));
750381a2a9aSdr }
751381a2a9aSdr 
752381a2a9aSdr /*
753381a2a9aSdr  * Get next interface from the current list of IPv6 physical network interfaces
754381a2a9aSdr  */
755381a2a9aSdr static phy_if_t
ipv6_phygetnext(net_handle_t neti,phy_if_t phy_ifdata)7567ddc9b1aSDarren Reed ipv6_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
757381a2a9aSdr {
7587ddc9b1aSDarren Reed 	netstack_t *ns;
7597ddc9b1aSDarren Reed 
7607ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
761f4b3ec61Sdh 	ASSERT(ns != NULL);
762f4b3ec61Sdh 	return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip));
763381a2a9aSdr }
764381a2a9aSdr 
765381a2a9aSdr /*
766381a2a9aSdr  * Determine if a network interface name exists for IPv4
767381a2a9aSdr  */
768381a2a9aSdr static phy_if_t
ip_phylookup(net_handle_t neti,const char * name)7697ddc9b1aSDarren Reed ip_phylookup(net_handle_t neti, const char *name)
770381a2a9aSdr {
7717ddc9b1aSDarren Reed 	netstack_t *ns;
7727ddc9b1aSDarren Reed 
7737ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
774f4b3ec61Sdh 	ASSERT(ns != NULL);
775f4b3ec61Sdh 	return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip));
776381a2a9aSdr }
777381a2a9aSdr 
778381a2a9aSdr /*
779381a2a9aSdr  * Determine if a network interface name exists for IPv6
780381a2a9aSdr  */
781381a2a9aSdr static phy_if_t
ipv6_phylookup(net_handle_t neti,const char * name)7827ddc9b1aSDarren Reed ipv6_phylookup(net_handle_t neti, const char *name)
783381a2a9aSdr {
7847ddc9b1aSDarren Reed 	netstack_t *ns;
7857ddc9b1aSDarren Reed 
7867ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
787f4b3ec61Sdh 	ASSERT(ns != NULL);
788f4b3ec61Sdh 	return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip));
789381a2a9aSdr }
790381a2a9aSdr 
791381a2a9aSdr /*
792381a2a9aSdr  * Implement looking up an ill_t based on the name supplied and matching
793381a2a9aSdr  * it up with either IPv4 or IPv6.  ill_get_ifindex_by_name() is not used
794381a2a9aSdr  * because it does not match on the address family in addition to the name.
795381a2a9aSdr  */
796381a2a9aSdr static phy_if_t
ip_phylookup_impl(const char * name,boolean_t isv6,ip_stack_t * ipst)797f4b3ec61Sdh ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst)
798381a2a9aSdr {
799381a2a9aSdr 	phy_if_t phy;
800381a2a9aSdr 	ill_t *ill;
801381a2a9aSdr 
802bd670b35SErik Nordmark 	ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, ipst);
803381a2a9aSdr 	if (ill == NULL)
804381a2a9aSdr 		return (0);
805381a2a9aSdr 
806e11c3f44Smeem 	phy = ill->ill_phyint->phyint_ifindex;
807381a2a9aSdr 
808381a2a9aSdr 	ill_refrele(ill);
809381a2a9aSdr 
810381a2a9aSdr 	return (phy);
811381a2a9aSdr }
812381a2a9aSdr 
813381a2a9aSdr /*
814381a2a9aSdr  * Get next interface from the current list of IPv4 logical network interfaces
815381a2a9aSdr  */
816381a2a9aSdr static lif_if_t
ip_lifgetnext(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata)8177ddc9b1aSDarren Reed ip_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
818381a2a9aSdr {
8197ddc9b1aSDarren Reed 	netstack_t *ns;
8207ddc9b1aSDarren Reed 
8217ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
822f4b3ec61Sdh 	ASSERT(ns != NULL);
823f4b3ec61Sdh 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE,
824f4b3ec61Sdh 	    ns->netstack_ip));
825381a2a9aSdr }
826381a2a9aSdr 
827381a2a9aSdr /*
828381a2a9aSdr  * Get next interface from the current list of IPv6 logical network interfaces
829381a2a9aSdr  */
830381a2a9aSdr static lif_if_t
ipv6_lifgetnext(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata)8317ddc9b1aSDarren Reed ipv6_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
832381a2a9aSdr {
8337ddc9b1aSDarren Reed 	netstack_t *ns;
8347ddc9b1aSDarren Reed 
8357ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
836f4b3ec61Sdh 	ASSERT(ns != NULL);
837f4b3ec61Sdh 	return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE,
838f4b3ec61Sdh 	    ns->netstack_ip));
839381a2a9aSdr }
840381a2a9aSdr 
841381a2a9aSdr /*
842381a2a9aSdr  * Shared implementation to get next interface from the current list of
843381a2a9aSdr  * logical network interfaces
844381a2a9aSdr  */
845381a2a9aSdr static lif_if_t
ip_lifgetnext_impl(phy_if_t phy_ifdata,lif_if_t ifdata,boolean_t isv6,ip_stack_t * ipst)846f4b3ec61Sdh ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
847f4b3ec61Sdh     ip_stack_t *ipst)
848381a2a9aSdr {
849381a2a9aSdr 	lif_if_t newidx, oldidx;
850381a2a9aSdr 	boolean_t nextok;
851381a2a9aSdr 	ipif_t *ipif;
852381a2a9aSdr 	ill_t *ill;
853381a2a9aSdr 
854bd670b35SErik Nordmark 	ill = ill_lookup_on_ifindex(phy_ifdata, isv6, ipst);
855381a2a9aSdr 	if (ill == NULL)
856381a2a9aSdr 		return (0);
857381a2a9aSdr 
858381a2a9aSdr 	if (ifdata != 0) {
859381a2a9aSdr 		oldidx = UNMAP_IPIF_ID(ifdata);
860381a2a9aSdr 		nextok = B_FALSE;
861381a2a9aSdr 	} else {
862381a2a9aSdr 		oldidx = 0;
863381a2a9aSdr 		nextok = B_TRUE;
864381a2a9aSdr 	}
865381a2a9aSdr 
866381a2a9aSdr 	mutex_enter(&ill->ill_lock);
867381a2a9aSdr 	if (ill->ill_state_flags & ILL_CONDEMNED) {
868381a2a9aSdr 		mutex_exit(&ill->ill_lock);
869381a2a9aSdr 		ill_refrele(ill);
870381a2a9aSdr 		return (0);
871381a2a9aSdr 	}
872381a2a9aSdr 
873381a2a9aSdr 	/*
874381a2a9aSdr 	 * It's safe to iterate the ill_ipif list when holding an ill_lock.
875381a2a9aSdr 	 * And it's also safe to access ipif_id without ipif refhold.
876e11c3f44Smeem 	 * See the field access rules in ip.h.
877381a2a9aSdr 	 */
878381a2a9aSdr 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
879381a2a9aSdr 		if (!IPIF_CAN_LOOKUP(ipif))
880381a2a9aSdr 			continue;
881381a2a9aSdr 		if (nextok) {
882381a2a9aSdr 			ipif_refhold_locked(ipif);
883381a2a9aSdr 			break;
884381a2a9aSdr 		} else if (oldidx == ipif->ipif_id) {
885381a2a9aSdr 			nextok = B_TRUE;
886381a2a9aSdr 		}
887381a2a9aSdr 	}
888381a2a9aSdr 
889381a2a9aSdr 	mutex_exit(&ill->ill_lock);
890381a2a9aSdr 	ill_refrele(ill);
891381a2a9aSdr 
892381a2a9aSdr 	if (ipif == NULL)
893381a2a9aSdr 		return (0);
894381a2a9aSdr 
895381a2a9aSdr 	newidx = ipif->ipif_id;
896381a2a9aSdr 	ipif_refrele(ipif);
897381a2a9aSdr 
898381a2a9aSdr 	return (MAP_IPIF_ID(newidx));
899381a2a9aSdr }
900381a2a9aSdr 
901381a2a9aSdr /*
902381a2a9aSdr  * Inject an IPv4 packet to or from an interface
903381a2a9aSdr  */
904381a2a9aSdr static int
ip_inject(net_handle_t neti,inject_t style,net_inject_t * packet)9057ddc9b1aSDarren Reed ip_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
906381a2a9aSdr {
9077ddc9b1aSDarren Reed 	netstack_t *ns;
9087ddc9b1aSDarren Reed 
9097ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
910f4b3ec61Sdh 	ASSERT(ns != NULL);
911f4b3ec61Sdh 	return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip));
912381a2a9aSdr }
913381a2a9aSdr 
914381a2a9aSdr 
915381a2a9aSdr /*
916381a2a9aSdr  * Inject an IPv6 packet to or from an interface
917381a2a9aSdr  */
918381a2a9aSdr static int
ipv6_inject(net_handle_t neti,inject_t style,net_inject_t * packet)9197ddc9b1aSDarren Reed ipv6_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
920381a2a9aSdr {
9217ddc9b1aSDarren Reed 	netstack_t *ns;
9227ddc9b1aSDarren Reed 
9237ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
924f4b3ec61Sdh 	return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip));
925381a2a9aSdr }
926381a2a9aSdr 
927381a2a9aSdr /*
928381a2a9aSdr  * Shared implementation to inject a packet to or from an interface
929381a2a9aSdr  * Return value:
930381a2a9aSdr  *   0: successful
931381a2a9aSdr  *  -1: memory allocation failed
932381a2a9aSdr  *   1: other errors
933381a2a9aSdr  */
934381a2a9aSdr static int
ip_inject_impl(inject_t style,net_inject_t * packet,boolean_t isv6,ip_stack_t * ipst)935f4b3ec61Sdh ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6,
936f4b3ec61Sdh     ip_stack_t *ipst)
937381a2a9aSdr {
938381a2a9aSdr 	ddi_taskq_t *tq = NULL;
939f4b3ec61Sdh 	void (* func)(void *);
940381a2a9aSdr 	injection_t *inject;
941381a2a9aSdr 	mblk_t *mp;
942381a2a9aSdr 
943381a2a9aSdr 	ASSERT(packet != NULL);
944381a2a9aSdr 	ASSERT(packet->ni_packet != NULL);
945381a2a9aSdr 	ASSERT(packet->ni_packet->b_datap->db_type == M_DATA);
946381a2a9aSdr 
947381a2a9aSdr 	switch (style) {
948381a2a9aSdr 	case NI_QUEUE_IN:
949381a2a9aSdr 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
950381a2a9aSdr 		if (inject == NULL)
951381a2a9aSdr 			return (-1);
952381a2a9aSdr 		inject->inj_data = *packet;
953381a2a9aSdr 		inject->inj_isv6 = isv6;
954381a2a9aSdr 		/*
955381a2a9aSdr 		 * deliver up into the kernel, immitating its reception by a
956381a2a9aSdr 		 * network interface, add to list and schedule timeout
957381a2a9aSdr 		 */
958381a2a9aSdr 		func = ip_ni_queue_in_func;
959381a2a9aSdr 		tq = eventq_queue_in;
960381a2a9aSdr 		break;
961381a2a9aSdr 
962381a2a9aSdr 	case NI_QUEUE_OUT:
963381a2a9aSdr 		inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP);
964381a2a9aSdr 		if (inject == NULL)
965381a2a9aSdr 			return (-1);
966381a2a9aSdr 		inject->inj_data = *packet;
967381a2a9aSdr 		inject->inj_isv6 = isv6;
968381a2a9aSdr 		/*
969381a2a9aSdr 		 * deliver out of the kernel, as if it were being sent via a
970381a2a9aSdr 		 * raw socket so that IPFilter will see it again, add to list
971381a2a9aSdr 		 * and schedule timeout
972381a2a9aSdr 		 */
973381a2a9aSdr 		func = ip_ni_queue_out_func;
974381a2a9aSdr 		tq = eventq_queue_out;
975381a2a9aSdr 		break;
976381a2a9aSdr 
977bd670b35SErik Nordmark 	case NI_DIRECT_OUT: {
978bd670b35SErik Nordmark 		struct sockaddr *sock;
979381a2a9aSdr 
980bd670b35SErik Nordmark 		mp = packet->ni_packet;
981381a2a9aSdr 
982bd670b35SErik Nordmark 		sock = (struct sockaddr *)&packet->ni_addr;
983bd670b35SErik Nordmark 		/*
984bd670b35SErik Nordmark 		 * ipfil_sendpkt was provided by surya to ease the
985bd670b35SErik Nordmark 		 * problems associated with sending out a packet.
986bd670b35SErik Nordmark 		 */
987bd670b35SErik Nordmark 		switch (ipfil_sendpkt(sock, mp, packet->ni_physical,
988bd670b35SErik Nordmark 		    netstackid_to_zoneid(
989bd670b35SErik Nordmark 		    ipst->ips_netstack->netstack_stackid))) {
990bd670b35SErik Nordmark 		case 0 :
991bd670b35SErik Nordmark 		case EINPROGRESS:
992381a2a9aSdr 			return (0);
993bd670b35SErik Nordmark 		case ECOMM :
994bd670b35SErik Nordmark 		case ENONET :
995bd670b35SErik Nordmark 			return (1);
996bd670b35SErik Nordmark 		default :
997bd670b35SErik Nordmark 			return (1);
998381a2a9aSdr 		}
999bd670b35SErik Nordmark 		/* NOTREACHED */
1000bd670b35SErik Nordmark 	}
1001381a2a9aSdr 	default:
1002381a2a9aSdr 		freemsg(packet->ni_packet);
1003381a2a9aSdr 		return (1);
1004381a2a9aSdr 	}
1005381a2a9aSdr 
1006bd670b35SErik Nordmark 	ASSERT(tq != NULL);
1007381a2a9aSdr 
1008bd670b35SErik Nordmark 	inject->inj_ptr = ipst;
1009bd670b35SErik Nordmark 	if (ddi_taskq_dispatch(tq, func, (void *)inject,
1010bd670b35SErik Nordmark 	    DDI_SLEEP) == DDI_FAILURE) {
1011bd670b35SErik Nordmark 		ip2dbg(("ip_inject:  ddi_taskq_dispatch failed\n"));
1012bd670b35SErik Nordmark 		freemsg(packet->ni_packet);
1013bd670b35SErik Nordmark 		return (1);
1014bd670b35SErik Nordmark 	}
1015381a2a9aSdr 	return (0);
1016381a2a9aSdr }
1017381a2a9aSdr 
1018381a2a9aSdr /*
1019381a2a9aSdr  * Find the interface used for traffic to a given IPv4 address
1020381a2a9aSdr  */
1021381a2a9aSdr static phy_if_t
ip_routeto(net_handle_t neti,struct sockaddr * address,struct sockaddr * next)10227ddc9b1aSDarren Reed ip_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
1023381a2a9aSdr {
10247ddc9b1aSDarren Reed 	netstack_t *ns;
10257ddc9b1aSDarren Reed 
1026381a2a9aSdr 	ASSERT(address != NULL);
1027381a2a9aSdr 
1028381a2a9aSdr 	if (address->sa_family != AF_INET)
1029381a2a9aSdr 		return (0);
10307ddc9b1aSDarren Reed 
10317ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
10327ddc9b1aSDarren Reed 	ASSERT(ns != NULL);
10337ddc9b1aSDarren Reed 
10347ddc9b1aSDarren Reed 	return (ip_routeto_impl(address, next, ns->netstack_ip));
1035381a2a9aSdr }
1036381a2a9aSdr 
1037381a2a9aSdr /*
1038381a2a9aSdr  * Find the interface used for traffic to a given IPv6 address
1039381a2a9aSdr  */
1040381a2a9aSdr static phy_if_t
ipv6_routeto(net_handle_t neti,struct sockaddr * address,struct sockaddr * next)10417ddc9b1aSDarren Reed ipv6_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
1042381a2a9aSdr {
10437ddc9b1aSDarren Reed 	netstack_t *ns;
10447ddc9b1aSDarren Reed 
1045381a2a9aSdr 	ASSERT(address != NULL);
1046381a2a9aSdr 
1047381a2a9aSdr 	if (address->sa_family != AF_INET6)
1048381a2a9aSdr 		return (0);
10497ddc9b1aSDarren Reed 
10507ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
10517ddc9b1aSDarren Reed 	ASSERT(ns != NULL);
10527ddc9b1aSDarren Reed 
10537ddc9b1aSDarren Reed 	return (ip_routeto_impl(address, next, ns->netstack_ip));
1054381a2a9aSdr }
1055381a2a9aSdr 
1056381a2a9aSdr 
1057381a2a9aSdr /*
10587ddc9b1aSDarren Reed  * Find the interface used for traffic to an address.
10597ddc9b1aSDarren Reed  * For lint reasons, next/next6/sin/sin6 are all declared and assigned
10607ddc9b1aSDarren Reed  * a value at the top.  The alternative would end up with two bunches
10617ddc9b1aSDarren Reed  * of assignments, with each bunch setting half to NULL.
1062381a2a9aSdr  */
1063381a2a9aSdr static phy_if_t
ip_routeto_impl(struct sockaddr * address,struct sockaddr * nexthop,ip_stack_t * ipst)10647ddc9b1aSDarren Reed ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop,
10657ddc9b1aSDarren Reed     ip_stack_t *ipst)
1066381a2a9aSdr {
10677ddc9b1aSDarren Reed 	struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop;
10687ddc9b1aSDarren Reed 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address;
10697ddc9b1aSDarren Reed 	struct sockaddr_in *next = (struct sockaddr_in *)nexthop;
10707ddc9b1aSDarren Reed 	struct sockaddr_in *sin = (struct sockaddr_in *)address;
1071381a2a9aSdr 	ire_t *ire;
1072bd670b35SErik Nordmark 	ire_t *nexthop_ire;
1073381a2a9aSdr 	phy_if_t phy_if;
107472680cf5SDarren Reed 	zoneid_t zoneid;
107572680cf5SDarren Reed 
107672680cf5SDarren Reed 	zoneid = netstackid_to_zoneid(ipst->ips_netstack->netstack_stackid);
1077381a2a9aSdr 
1078381a2a9aSdr 	if (address->sa_family == AF_INET6) {
1079bd670b35SErik Nordmark 		ire = ire_route_recursive_v6(&sin6->sin6_addr, 0, NULL,
10809e3469d3SErik Nordmark 		    zoneid, NULL, MATCH_IRE_DSTONLY, IRR_ALLOCATE, 0, ipst,
10819e3469d3SErik Nordmark 		    NULL, NULL, NULL);
1082381a2a9aSdr 	} else {
1083bd670b35SErik Nordmark 		ire = ire_route_recursive_v4(sin->sin_addr.s_addr, 0, NULL,
10849e3469d3SErik Nordmark 		    zoneid, NULL, MATCH_IRE_DSTONLY, IRR_ALLOCATE, 0, ipst,
10859e3469d3SErik Nordmark 		    NULL, NULL, NULL);
1086381a2a9aSdr 	}
1087bd670b35SErik Nordmark 	ASSERT(ire != NULL);
10887ddc9b1aSDarren Reed 	/*
10897ddc9b1aSDarren Reed 	 * For some destinations, we have routes that are dead ends, so
10907ddc9b1aSDarren Reed 	 * return to indicate that no physical interface can be used to
10917ddc9b1aSDarren Reed 	 * reach the destination.
10927ddc9b1aSDarren Reed 	 */
1093bd670b35SErik Nordmark 	if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
10947ddc9b1aSDarren Reed 		ire_refrele(ire);
1095*63d2ef3cSToomas Soome 		return ((uintptr_t)NULL);
10967ddc9b1aSDarren Reed 	}
10977ddc9b1aSDarren Reed 
1098bd670b35SErik Nordmark 	nexthop_ire = ire_nexthop(ire);
1099bd670b35SErik Nordmark 	if (nexthop_ire == NULL) {
1100bd670b35SErik Nordmark 		ire_refrele(ire);
1101*63d2ef3cSToomas Soome 		return ((uintptr_t)NULL);
1102bd670b35SErik Nordmark 	}
1103bd670b35SErik Nordmark 	if (nexthop_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
1104bd670b35SErik Nordmark 		ire_refrele(nexthop_ire);
110567c1caeeSnordmark 		ire_refrele(ire);
1106*63d2ef3cSToomas Soome 		return ((uintptr_t)NULL);
110767c1caeeSnordmark 	}
1108381a2a9aSdr 
1109bd670b35SErik Nordmark 	ASSERT(nexthop_ire->ire_ill != NULL);
1110bd670b35SErik Nordmark 
11117ddc9b1aSDarren Reed 	if (nexthop != NULL) {
11127ddc9b1aSDarren Reed 		if (address->sa_family == AF_INET6) {
1113bd670b35SErik Nordmark 			next6->sin6_addr = nexthop_ire->ire_addr_v6;
11147ddc9b1aSDarren Reed 		} else {
1115bd670b35SErik Nordmark 			next->sin_addr.s_addr = nexthop_ire->ire_addr;
11167ddc9b1aSDarren Reed 		}
11177ddc9b1aSDarren Reed 	}
11187ddc9b1aSDarren Reed 
1119bd670b35SErik Nordmark 	phy_if = (phy_if_t)nexthop_ire->ire_ill->ill_phyint->phyint_ifindex;
1120381a2a9aSdr 	ire_refrele(ire);
1121bd670b35SErik Nordmark 	ire_refrele(nexthop_ire);
1122381a2a9aSdr 
1123381a2a9aSdr 	return (phy_if);
1124381a2a9aSdr }
1125381a2a9aSdr 
1126381a2a9aSdr /*
1127381a2a9aSdr  * Determine if checksumming is being used for the given packet.
1128381a2a9aSdr  *
1129381a2a9aSdr  * Return value:
1130381a2a9aSdr  *   NET_HCK_NONE: full checksum recalculation is required
1131381a2a9aSdr  *   NET_HCK_L3_FULL: full layer 3 checksum
1132381a2a9aSdr  *   NET_HCK_L4_FULL: full layer 4 checksum
1133381a2a9aSdr  *   NET_HCK_L4_PART: partial layer 4 checksum
1134381a2a9aSdr  */
11357ddc9b1aSDarren Reed /*ARGSUSED*/
1136381a2a9aSdr static int
ip_ispartialchecksum(net_handle_t neti,mblk_t * mp)11377ddc9b1aSDarren Reed ip_ispartialchecksum(net_handle_t neti, mblk_t *mp)
1138381a2a9aSdr {
1139381a2a9aSdr 	int ret = 0;
1140381a2a9aSdr 
1141381a2a9aSdr 	ASSERT(mp != NULL);
1142381a2a9aSdr 
1143381a2a9aSdr 	if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) {
1144381a2a9aSdr 		ret |= (int)NET_HCK_L4_FULL;
1145381a2a9aSdr 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
1146381a2a9aSdr 			ret |= (int)NET_HCK_L3_FULL;
1147381a2a9aSdr 	}
1148381a2a9aSdr 	if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) {
1149381a2a9aSdr 		ret |= (int)NET_HCK_L4_PART;
1150381a2a9aSdr 		if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0)
1151381a2a9aSdr 			ret |= (int)NET_HCK_L3_FULL;
1152381a2a9aSdr 	}
1153381a2a9aSdr 
1154381a2a9aSdr 	return (ret);
1155381a2a9aSdr }
1156381a2a9aSdr 
1157381a2a9aSdr /*
1158381a2a9aSdr  * Return true or false, indicating whether the network and transport
1159381a2a9aSdr  * headers are correct.  Use the capabilities flags and flags set in the
1160381a2a9aSdr  * dblk_t to determine whether or not the checksum is valid.
1161381a2a9aSdr  *
1162381a2a9aSdr  * Return:
1163381a2a9aSdr  *   0: the checksum was incorrect
1164381a2a9aSdr  *   1: the original checksum was correct
1165381a2a9aSdr  */
11667ddc9b1aSDarren Reed /*ARGSUSED*/
1167381a2a9aSdr static int
ip_isvalidchecksum(net_handle_t neti,mblk_t * mp)11687ddc9b1aSDarren Reed ip_isvalidchecksum(net_handle_t neti, mblk_t *mp)
1169381a2a9aSdr {
1170381a2a9aSdr 	unsigned char *wptr;
1171381a2a9aSdr 	ipha_t *ipha = (ipha_t *)mp->b_rptr;
1172381a2a9aSdr 	int hlen;
1173381a2a9aSdr 	int ret;
1174381a2a9aSdr 
1175381a2a9aSdr 	ASSERT(mp != NULL);
1176381a2a9aSdr 
1177381a2a9aSdr 	if (dohwcksum &&
11780dc2366fSVenugopal Iyer 	    ((DB_CKSUM16(mp) != 0xFFFF &&
11790dc2366fSVenugopal Iyer 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM)) ||
11800dc2366fSVenugopal Iyer 	    (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK)) &&
11810dc2366fSVenugopal Iyer 	    (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM_OK))
1182381a2a9aSdr 		return (1);
1183381a2a9aSdr 
1184381a2a9aSdr 	hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2;
1185381a2a9aSdr 
1186381a2a9aSdr 	/*
1187381a2a9aSdr 	 * Check that the mblk being passed in has enough data in it
1188381a2a9aSdr 	 * before blindly checking ip_cksum.
1189381a2a9aSdr 	 */
1190381a2a9aSdr 	if (msgdsize(mp) < hlen)
1191381a2a9aSdr 		return (0);
1192381a2a9aSdr 
1193381a2a9aSdr 	if (mp->b_wptr < mp->b_rptr + hlen) {
1194381a2a9aSdr 		if (pullupmsg(mp, hlen) == 0)
1195381a2a9aSdr 			return (0);
1196381a2a9aSdr 		wptr = mp->b_wptr;
1197381a2a9aSdr 	} else {
1198381a2a9aSdr 		wptr = mp->b_wptr;
1199381a2a9aSdr 		mp->b_wptr = mp->b_rptr + hlen;
1200381a2a9aSdr 	}
1201381a2a9aSdr 
1202381a2a9aSdr 	if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum))
1203381a2a9aSdr 		ret = 1;
1204381a2a9aSdr 	else
1205381a2a9aSdr 		ret = 0;
1206381a2a9aSdr 	mp->b_wptr = wptr;
1207381a2a9aSdr 
1208381a2a9aSdr 	return (ret);
1209381a2a9aSdr }
1210381a2a9aSdr 
1211381a2a9aSdr /*
1212381a2a9aSdr  * Unsupported with IPv6
1213381a2a9aSdr  */
1214381a2a9aSdr /*ARGSUSED*/
1215381a2a9aSdr static int
ipv6_isvalidchecksum(net_handle_t neti,mblk_t * mp)12167ddc9b1aSDarren Reed ipv6_isvalidchecksum(net_handle_t neti, mblk_t *mp)
1217381a2a9aSdr {
1218381a2a9aSdr 	return (-1);
1219381a2a9aSdr }
1220381a2a9aSdr 
1221381a2a9aSdr /*
1222381a2a9aSdr  * Determine the network addresses for an IPv4 interface
1223381a2a9aSdr  */
1224381a2a9aSdr static int
ip_getlifaddr(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,size_t nelem,net_ifaddr_t type[],void * storage)12257ddc9b1aSDarren Reed ip_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
12267ddc9b1aSDarren Reed     size_t nelem, net_ifaddr_t type[], void *storage)
1227381a2a9aSdr {
12287ddc9b1aSDarren Reed 	netstack_t *ns;
12297ddc9b1aSDarren Reed 
12307ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
1231f4b3ec61Sdh 	ASSERT(ns != NULL);
1232381a2a9aSdr 	return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata,
1233f4b3ec61Sdh 	    nelem, type, storage, ns->netstack_ip));
1234381a2a9aSdr }
1235381a2a9aSdr 
1236381a2a9aSdr /*
1237381a2a9aSdr  * Determine the network addresses for an IPv6 interface
1238381a2a9aSdr  */
1239381a2a9aSdr static int
ipv6_getlifaddr(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,size_t nelem,net_ifaddr_t type[],void * storage)12407ddc9b1aSDarren Reed ipv6_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
12417ddc9b1aSDarren Reed     size_t nelem, net_ifaddr_t type[], void *storage)
1242381a2a9aSdr {
12437ddc9b1aSDarren Reed 	netstack_t *ns;
12447ddc9b1aSDarren Reed 
12457ddc9b1aSDarren Reed 	ns = neti->netd_stack->nts_netstack;
1246f4b3ec61Sdh 	ASSERT(ns != NULL);
1247381a2a9aSdr 	return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata,
1248f4b3ec61Sdh 	    nelem, type, storage, ns->netstack_ip));
1249381a2a9aSdr }
1250381a2a9aSdr 
1251381a2a9aSdr /*
1252381a2a9aSdr  * Shared implementation to determine the network addresses for an interface
1253381a2a9aSdr  */
1254381a2a9aSdr /* ARGSUSED */
1255381a2a9aSdr static int
ip_getlifaddr_impl(sa_family_t family,phy_if_t phy_ifdata,lif_if_t ifdata,size_t nelem,net_ifaddr_t type[],struct sockaddr * storage,ip_stack_t * ipst)1256381a2a9aSdr ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata,
1257381a2a9aSdr     lif_if_t ifdata, size_t nelem, net_ifaddr_t type[],
1258f4b3ec61Sdh     struct sockaddr *storage, ip_stack_t *ipst)
1259381a2a9aSdr {
1260381a2a9aSdr 	struct sockaddr_in6 *sin6;
1261381a2a9aSdr 	struct sockaddr_in *sin;
1262381a2a9aSdr 	lif_if_t ipifid;
1263381a2a9aSdr 	ipif_t *ipif;
1264381a2a9aSdr 	int i;
1265381a2a9aSdr 
1266381a2a9aSdr 	ASSERT(type != NULL);
1267381a2a9aSdr 	ASSERT(storage != NULL);
1268381a2a9aSdr 
1269381a2a9aSdr 	ipifid = UNMAP_IPIF_ID(ifdata);
1270381a2a9aSdr 
1271381a2a9aSdr 	if (family == AF_INET) {
1272381a2a9aSdr 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1273f4b3ec61Sdh 		    (uint_t)ipifid, B_FALSE, ipst)) == NULL)
1274381a2a9aSdr 			return (1);
1275381a2a9aSdr 
1276381a2a9aSdr 		sin = (struct sockaddr_in *)storage;
1277381a2a9aSdr 		for (i = 0; i < nelem; i++, sin++) {
1278381a2a9aSdr 			if (ip_getifaddr_type(AF_INET, ipif, type[i],
1279381a2a9aSdr 			    &sin->sin_addr) < 0) {
1280381a2a9aSdr 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
1281381a2a9aSdr 				    type[i]));
1282381a2a9aSdr 				ipif_refrele(ipif);
1283381a2a9aSdr 				return (1);
1284381a2a9aSdr 			}
12858ad74188SDarren Reed 			sin->sin_family = AF_INET;
1286381a2a9aSdr 		}
1287381a2a9aSdr 	} else {
1288381a2a9aSdr 		if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1289f4b3ec61Sdh 		    (uint_t)ipifid, B_TRUE, ipst)) == NULL)
1290381a2a9aSdr 			return (1);
1291381a2a9aSdr 
1292381a2a9aSdr 		sin6 = (struct sockaddr_in6 *)storage;
1293381a2a9aSdr 		for (i = 0; i < nelem; i++, sin6++) {
1294381a2a9aSdr 			if (ip_getifaddr_type(AF_INET6, ipif, type[i],
1295381a2a9aSdr 			    &sin6->sin6_addr) < 0) {
1296381a2a9aSdr 				ip2dbg(("ip_getlifaddr_impl failed type %d\n",
1297381a2a9aSdr 				    type[i]));
1298381a2a9aSdr 				ipif_refrele(ipif);
1299381a2a9aSdr 				return (1);
1300381a2a9aSdr 			}
13018ad74188SDarren Reed 			sin6->sin6_family = AF_INET6;
1302381a2a9aSdr 		}
1303381a2a9aSdr 	}
1304381a2a9aSdr 	ipif_refrele(ipif);
1305381a2a9aSdr 	return (0);
1306381a2a9aSdr }
1307381a2a9aSdr 
1308381a2a9aSdr /*
1309381a2a9aSdr  * ip_getlifaddr private function
1310381a2a9aSdr  */
1311381a2a9aSdr static int
ip_getifaddr_type(sa_family_t family,ipif_t * ill_ipif,lif_if_t type,void * storage)1312381a2a9aSdr ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif,
1313381a2a9aSdr     lif_if_t type, void *storage)
1314381a2a9aSdr {
1315381a2a9aSdr 	void *src_addr;
1316381a2a9aSdr 	int mem_size;
1317381a2a9aSdr 
1318381a2a9aSdr 	ASSERT(ill_ipif != NULL);
1319381a2a9aSdr 	ASSERT(storage != NULL);
1320381a2a9aSdr 
1321381a2a9aSdr 	if (family == AF_INET) {
1322381a2a9aSdr 		mem_size = sizeof (struct in_addr);
1323381a2a9aSdr 
1324381a2a9aSdr 		switch (type) {
1325381a2a9aSdr 		case NA_ADDRESS:
1326381a2a9aSdr 			src_addr = &(ill_ipif->ipif_lcl_addr);
1327381a2a9aSdr 			break;
1328381a2a9aSdr 		case NA_PEER:
1329381a2a9aSdr 			src_addr = &(ill_ipif->ipif_pp_dst_addr);
1330381a2a9aSdr 			break;
1331381a2a9aSdr 		case NA_BROADCAST:
1332381a2a9aSdr 			src_addr = &(ill_ipif->ipif_brd_addr);
1333381a2a9aSdr 			break;
1334381a2a9aSdr 		case NA_NETMASK:
1335381a2a9aSdr 			src_addr = &(ill_ipif->ipif_net_mask);
1336381a2a9aSdr 			break;
1337381a2a9aSdr 		default:
1338381a2a9aSdr 			return (-1);
1339381a2a9aSdr 			/*NOTREACHED*/
1340381a2a9aSdr 		}
1341381a2a9aSdr 	} else {
1342381a2a9aSdr 		mem_size = sizeof (struct in6_addr);
1343381a2a9aSdr 
1344381a2a9aSdr 		switch (type) {
1345381a2a9aSdr 		case NA_ADDRESS:
1346381a2a9aSdr 			src_addr = &(ill_ipif->ipif_v6lcl_addr);
1347381a2a9aSdr 			break;
1348381a2a9aSdr 		case NA_PEER:
1349381a2a9aSdr 			src_addr = &(ill_ipif->ipif_v6pp_dst_addr);
1350381a2a9aSdr 			break;
1351381a2a9aSdr 		case NA_BROADCAST:
1352381a2a9aSdr 			src_addr = &(ill_ipif->ipif_v6brd_addr);
1353381a2a9aSdr 			break;
1354381a2a9aSdr 		case NA_NETMASK:
1355381a2a9aSdr 			src_addr = &(ill_ipif->ipif_v6net_mask);
1356381a2a9aSdr 			break;
1357381a2a9aSdr 		default:
1358381a2a9aSdr 			return (-1);
1359381a2a9aSdr 			/*NOTREACHED*/
1360381a2a9aSdr 		}
1361381a2a9aSdr 	}
1362381a2a9aSdr 
1363381a2a9aSdr 	(void) memcpy(storage, src_addr, mem_size);
1364381a2a9aSdr 	return (1);
1365381a2a9aSdr }
1366381a2a9aSdr 
1367b127ac41SPhilip Kirk /*
1368b127ac41SPhilip Kirk  * Shared implementation to determine the zoneid associated with an IPv4/IPv6
1369b127ac41SPhilip Kirk  * address
1370b127ac41SPhilip Kirk  */
1371b127ac41SPhilip Kirk static int
ip_getlifzone_impl(sa_family_t family,phy_if_t phy_ifdata,lif_if_t ifdata,ip_stack_t * ipst,zoneid_t * zoneid)1372b127ac41SPhilip Kirk ip_getlifzone_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
1373b127ac41SPhilip Kirk     ip_stack_t *ipst, zoneid_t *zoneid)
1374b127ac41SPhilip Kirk {
1375b127ac41SPhilip Kirk 	ipif_t  *ipif;
1376b127ac41SPhilip Kirk 
1377b127ac41SPhilip Kirk 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1378b127ac41SPhilip Kirk 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
1379b127ac41SPhilip Kirk 	if (ipif == NULL)
1380b127ac41SPhilip Kirk 		return (-1);
1381b127ac41SPhilip Kirk 	*zoneid = IP_REAL_ZONEID(ipif->ipif_zoneid, ipst);
1382b127ac41SPhilip Kirk 	ipif_refrele(ipif);
1383b127ac41SPhilip Kirk 	return (0);
1384b127ac41SPhilip Kirk }
1385b127ac41SPhilip Kirk 
1386b127ac41SPhilip Kirk /*
1387b127ac41SPhilip Kirk  * Determine the zoneid associated with an IPv4 address
1388b127ac41SPhilip Kirk  */
1389b127ac41SPhilip Kirk static int
ip_getlifzone(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,zoneid_t * zoneid)1390b127ac41SPhilip Kirk ip_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1391b127ac41SPhilip Kirk     zoneid_t *zoneid)
1392b127ac41SPhilip Kirk {
1393b127ac41SPhilip Kirk 	return (ip_getlifzone_impl(AF_INET, phy_ifdata, ifdata,
1394b127ac41SPhilip Kirk 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
1395b127ac41SPhilip Kirk }
1396b127ac41SPhilip Kirk 
1397b127ac41SPhilip Kirk /*
1398b127ac41SPhilip Kirk  * Determine the zoneid associated with an IPv6 address
1399b127ac41SPhilip Kirk  */
1400b127ac41SPhilip Kirk static int
ipv6_getlifzone(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,zoneid_t * zoneid)1401b127ac41SPhilip Kirk ipv6_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1402b127ac41SPhilip Kirk     zoneid_t *zoneid)
1403b127ac41SPhilip Kirk {
1404b127ac41SPhilip Kirk 	return (ip_getlifzone_impl(AF_INET6, phy_ifdata, ifdata,
1405b127ac41SPhilip Kirk 	    neti->netd_stack->nts_netstack->netstack_ip, zoneid));
1406b127ac41SPhilip Kirk }
1407b127ac41SPhilip Kirk 
14080a0e9771SDarren Reed /*
14090a0e9771SDarren Reed  * The behaviour here mirrors that for the SIOCFLIFFLAGS ioctl where the
14100a0e9771SDarren Reed  * union of all of the relevant flags is returned.
14110a0e9771SDarren Reed  */
1412b127ac41SPhilip Kirk static int
ip_getlifflags_impl(sa_family_t family,phy_if_t phy_ifdata,lif_if_t ifdata,ip_stack_t * ipst,uint64_t * flags)1413b127ac41SPhilip Kirk ip_getlifflags_impl(sa_family_t family, phy_if_t phy_ifdata, lif_if_t ifdata,
1414b127ac41SPhilip Kirk     ip_stack_t *ipst, uint64_t *flags)
1415b127ac41SPhilip Kirk {
14160a0e9771SDarren Reed 	phyint_t *phyi;
1417b127ac41SPhilip Kirk 	ipif_t *ipif;
14180a0e9771SDarren Reed 	ill_t *ill;
14190a0e9771SDarren Reed 
1420bd670b35SErik Nordmark 	ill = ill_lookup_on_ifindex(phy_ifdata, (family == AF_INET6), ipst);
14210a0e9771SDarren Reed 	if (ill == NULL)
14220a0e9771SDarren Reed 		return (-1);
14230a0e9771SDarren Reed 	phyi = ill->ill_phyint;
1424b127ac41SPhilip Kirk 
1425b127ac41SPhilip Kirk 	ipif = ipif_getby_indexes((uint_t)phy_ifdata,
1426b127ac41SPhilip Kirk 	    UNMAP_IPIF_ID((uint_t)ifdata), (family == AF_INET6), ipst);
14270a0e9771SDarren Reed 	if (ipif == NULL) {
14280a0e9771SDarren Reed 		ill_refrele(ill);
1429b127ac41SPhilip Kirk 		return (-1);
14300a0e9771SDarren Reed 	}
14310a0e9771SDarren Reed 	*flags = ipif->ipif_flags | ill->ill_flags | phyi->phyint_flags;
1432b127ac41SPhilip Kirk 	ipif_refrele(ipif);
14330a0e9771SDarren Reed 	ill_refrele(ill);
1434b127ac41SPhilip Kirk 	return (0);
1435b127ac41SPhilip Kirk }
1436b127ac41SPhilip Kirk 
1437b127ac41SPhilip Kirk static int
ip_getlifflags(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,uint64_t * flags)1438b127ac41SPhilip Kirk ip_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1439b127ac41SPhilip Kirk     uint64_t *flags)
1440b127ac41SPhilip Kirk {
1441b127ac41SPhilip Kirk 	return (ip_getlifflags_impl(AF_INET, phy_ifdata, ifdata,
1442b127ac41SPhilip Kirk 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
1443b127ac41SPhilip Kirk }
1444b127ac41SPhilip Kirk 
1445b127ac41SPhilip Kirk static int
ipv6_getlifflags(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,uint64_t * flags)1446b127ac41SPhilip Kirk ipv6_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1447b127ac41SPhilip Kirk     uint64_t *flags)
1448b127ac41SPhilip Kirk {
1449b127ac41SPhilip Kirk 	return (ip_getlifflags_impl(AF_INET6, phy_ifdata, ifdata,
1450b127ac41SPhilip Kirk 	    neti->netd_stack->nts_netstack->netstack_ip, flags));
1451b127ac41SPhilip Kirk }
1452b127ac41SPhilip Kirk 
1453381a2a9aSdr /*
1454381a2a9aSdr  * Deliver packet up into the kernel, immitating its reception by a
1455381a2a9aSdr  * network interface.
1456381a2a9aSdr  */
1457381a2a9aSdr static void
ip_ni_queue_in_func(void * inject)1458381a2a9aSdr ip_ni_queue_in_func(void *inject)
1459381a2a9aSdr {
1460381a2a9aSdr 	ip_ni_queue_func_impl(inject, B_FALSE);
1461381a2a9aSdr }
1462381a2a9aSdr 
1463381a2a9aSdr /*
1464381a2a9aSdr  * Deliver out of the kernel, as if it were being sent via a
1465381a2a9aSdr  * raw socket so that IPFilter will see it again.
1466381a2a9aSdr  */
1467381a2a9aSdr static void
ip_ni_queue_out_func(void * inject)1468381a2a9aSdr ip_ni_queue_out_func(void *inject)
1469381a2a9aSdr {
1470381a2a9aSdr 	ip_ni_queue_func_impl(inject, B_TRUE);
1471381a2a9aSdr }
1472381a2a9aSdr 
1473381a2a9aSdr /*
1474381a2a9aSdr  * Shared implementation for inject via ip_output and ip_input
1475381a2a9aSdr  */
1476381a2a9aSdr static void
ip_ni_queue_func_impl(injection_t * inject,boolean_t out)1477381a2a9aSdr ip_ni_queue_func_impl(injection_t *inject,  boolean_t out)
1478381a2a9aSdr {
1479381a2a9aSdr 	net_inject_t *packet;
1480381a2a9aSdr 	ill_t *ill;
1481f4b3ec61Sdh 	ip_stack_t *ipst = (ip_stack_t *)inject->inj_ptr;
1482bd670b35SErik Nordmark 	ip_xmit_attr_t	ixas;
1483381a2a9aSdr 
1484381a2a9aSdr 	ASSERT(inject != NULL);
1485381a2a9aSdr 	packet = &inject->inj_data;
1486381a2a9aSdr 	ASSERT(packet->ni_packet != NULL);
1487381a2a9aSdr 
1488381a2a9aSdr 	if (out == 0) {
1489bd670b35SErik Nordmark 		ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical,
1490bd670b35SErik Nordmark 		    inject->inj_isv6, ipst);
1491bd670b35SErik Nordmark 
1492bd670b35SErik Nordmark 		if (ill == NULL) {
1493bd670b35SErik Nordmark 			kmem_free(inject, sizeof (*inject));
1494bd670b35SErik Nordmark 			return;
1495bd670b35SErik Nordmark 		}
1496bd670b35SErik Nordmark 
1497381a2a9aSdr 		if (inject->inj_isv6) {
1498bd670b35SErik Nordmark 			ip_input_v6(ill, NULL, packet->ni_packet, NULL);
1499381a2a9aSdr 		} else {
1500da14cebeSEric Cheng 			ip_input(ill, NULL, packet->ni_packet, NULL);
1501381a2a9aSdr 		}
1502381a2a9aSdr 		ill_refrele(ill);
1503bd670b35SErik Nordmark 	} else {
1504bd670b35SErik Nordmark 		bzero(&ixas, sizeof (ixas));
1505bd670b35SErik Nordmark 		ixas.ixa_ifindex = packet->ni_physical;
1506bd670b35SErik Nordmark 		ixas.ixa_ipst = ipst;
1507381a2a9aSdr 		if (inject->inj_isv6) {
1508bd670b35SErik Nordmark 			ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
1509381a2a9aSdr 		} else {
1510bd670b35SErik Nordmark 			ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4;
1511381a2a9aSdr 		}
15123e87ae12SSowmini Varadhan 		ixas.ixa_flags &= ~IXAF_VERIFY_SOURCE;
1513bd670b35SErik Nordmark 		(void) ip_output_simple(packet->ni_packet, &ixas);
1514bd670b35SErik Nordmark 		ixa_cleanup(&ixas);
1515381a2a9aSdr 	}
1516381a2a9aSdr 
1517381a2a9aSdr 	kmem_free(inject, sizeof (*inject));
1518381a2a9aSdr }
1519381a2a9aSdr 
1520381a2a9aSdr /*
1521381a2a9aSdr  * taskq function for nic events.
1522381a2a9aSdr  */
1523381a2a9aSdr void
ip_ne_queue_func(void * arg)1524381a2a9aSdr ip_ne_queue_func(void *arg)
1525381a2a9aSdr {
15267ddc9b1aSDarren Reed 	hook_event_token_t hr;
15277ddc9b1aSDarren Reed 	hook_nic_event_int_t *info = (hook_nic_event_int_t *)arg;
15287ddc9b1aSDarren Reed 	ip_stack_t *ipst;
15297ddc9b1aSDarren Reed 	netstack_t *ns;
1530381a2a9aSdr 
15317ddc9b1aSDarren Reed 	ns = netstack_find_by_stackid(info->hnei_stackid);
15327ddc9b1aSDarren Reed 	if (ns == NULL)
15337ddc9b1aSDarren Reed 		goto done;
15347ddc9b1aSDarren Reed 
15357ddc9b1aSDarren Reed 	ipst = ns->netstack_ip;
15367ddc9b1aSDarren Reed 	if (ipst == NULL)
15377ddc9b1aSDarren Reed 		goto done;
1538381a2a9aSdr 
15397ddc9b1aSDarren Reed 	hr = (info->hnei_event.hne_protocol == ipst->ips_ipv6_net_data) ?
15407ddc9b1aSDarren Reed 	    ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
15417ddc9b1aSDarren Reed 	(void) hook_run(info->hnei_event.hne_protocol->netd_hooks, hr,
15427ddc9b1aSDarren Reed 	    (hook_data_t)&info->hnei_event);
15437ddc9b1aSDarren Reed 
15447ddc9b1aSDarren Reed done:
15457ddc9b1aSDarren Reed 	if (ns != NULL)
15467ddc9b1aSDarren Reed 		netstack_rele(ns);
15477ddc9b1aSDarren Reed 	kmem_free(info->hnei_event.hne_data, info->hnei_event.hne_datalen);
15487ddc9b1aSDarren Reed 	kmem_free(arg, sizeof (hook_nic_event_int_t));
1549381a2a9aSdr }
1550bd670b35SErik Nordmark 
1551bd670b35SErik Nordmark /*
1552bd670b35SErik Nordmark  * Initialize ARP hook family and events
1553bd670b35SErik Nordmark  */
1554bd670b35SErik Nordmark void
arp_hook_init(ip_stack_t * ipst)1555bd670b35SErik Nordmark arp_hook_init(ip_stack_t *ipst)
1556bd670b35SErik Nordmark {
1557bd670b35SErik Nordmark 	HOOK_FAMILY_INIT(&ipst->ips_arproot, Hn_ARP);
1558bd670b35SErik Nordmark 	if (net_family_register(ipst->ips_arp_net_data, &ipst->ips_arproot)
1559bd670b35SErik Nordmark 	    != 0) {
1560bd670b35SErik Nordmark 		cmn_err(CE_NOTE, "arp_hook_init"
1561bd670b35SErik Nordmark 		    "net_family_register failed for arp");
1562bd670b35SErik Nordmark 	}
1563bd670b35SErik Nordmark 
1564bd670b35SErik Nordmark 	HOOK_EVENT_INIT(&ipst->ips_arp_physical_in_event, NH_PHYSICAL_IN);
1565bd670b35SErik Nordmark 	ipst->ips_arp_physical_in = net_event_register(ipst->ips_arp_net_data,
1566bd670b35SErik Nordmark 	    &ipst->ips_arp_physical_in_event);
1567bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_in == NULL) {
1568bd670b35SErik Nordmark 		cmn_err(CE_NOTE, "arp_hook_init: "
1569bd670b35SErik Nordmark 		    "net_event_register failed for arp/physical_in");
1570bd670b35SErik Nordmark 	}
1571bd670b35SErik Nordmark 
1572bd670b35SErik Nordmark 	HOOK_EVENT_INIT(&ipst->ips_arp_physical_out_event, NH_PHYSICAL_OUT);
1573bd670b35SErik Nordmark 	ipst->ips_arp_physical_out = net_event_register(ipst->ips_arp_net_data,
1574bd670b35SErik Nordmark 	    &ipst->ips_arp_physical_out_event);
1575bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_out == NULL) {
1576bd670b35SErik Nordmark 		cmn_err(CE_NOTE, "arp_hook_init: "
1577bd670b35SErik Nordmark 		    "net_event_register failed for arp/physical_out");
1578bd670b35SErik Nordmark 	}
1579bd670b35SErik Nordmark 
1580bd670b35SErik Nordmark 	HOOK_EVENT_INIT(&ipst->ips_arp_nic_events, NH_NIC_EVENTS);
1581bd670b35SErik Nordmark 	ipst->ips_arpnicevents = net_event_register(ipst->ips_arp_net_data,
1582bd670b35SErik Nordmark 	    &ipst->ips_arp_nic_events);
1583bd670b35SErik Nordmark 	if (ipst->ips_arpnicevents == NULL) {
1584bd670b35SErik Nordmark 		cmn_err(CE_NOTE, "arp_hook_init: "
1585bd670b35SErik Nordmark 		    "net_event_register failed for arp/nic_events");
1586bd670b35SErik Nordmark 	}
1587bd670b35SErik Nordmark }
1588bd670b35SErik Nordmark 
1589bd670b35SErik Nordmark void
arp_hook_destroy(ip_stack_t * ipst)1590bd670b35SErik Nordmark arp_hook_destroy(ip_stack_t *ipst)
1591bd670b35SErik Nordmark {
1592bd670b35SErik Nordmark 	if (ipst->ips_arpnicevents != NULL) {
1593bd670b35SErik Nordmark 		if (net_event_unregister(ipst->ips_arp_net_data,
1594bd670b35SErik Nordmark 		    &ipst->ips_arp_nic_events) == 0)
1595bd670b35SErik Nordmark 			ipst->ips_arpnicevents = NULL;
1596bd670b35SErik Nordmark 	}
1597bd670b35SErik Nordmark 
1598bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_out != NULL) {
1599bd670b35SErik Nordmark 		if (net_event_unregister(ipst->ips_arp_net_data,
1600bd670b35SErik Nordmark 		    &ipst->ips_arp_physical_out_event) == 0)
1601bd670b35SErik Nordmark 			ipst->ips_arp_physical_out = NULL;
1602bd670b35SErik Nordmark 	}
1603bd670b35SErik Nordmark 
1604bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_in != NULL) {
1605bd670b35SErik Nordmark 		if (net_event_unregister(ipst->ips_arp_net_data,
1606bd670b35SErik Nordmark 		    &ipst->ips_arp_physical_in_event) == 0)
1607bd670b35SErik Nordmark 			ipst->ips_arp_physical_in = NULL;
1608bd670b35SErik Nordmark 	}
1609bd670b35SErik Nordmark 
1610bd670b35SErik Nordmark 	(void) net_family_unregister(ipst->ips_arp_net_data,
1611bd670b35SErik Nordmark 	    &ipst->ips_arproot);
1612bd670b35SErik Nordmark }
1613bd670b35SErik Nordmark 
1614bd670b35SErik Nordmark void
arp_hook_shutdown(ip_stack_t * ipst)1615bd670b35SErik Nordmark arp_hook_shutdown(ip_stack_t *ipst)
1616bd670b35SErik Nordmark {
1617bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_in != NULL) {
1618bd670b35SErik Nordmark 		(void) net_event_shutdown(ipst->ips_arp_net_data,
1619bd670b35SErik Nordmark 		    &ipst->ips_arp_physical_in_event);
1620bd670b35SErik Nordmark 	}
1621bd670b35SErik Nordmark 	if (ipst->ips_arp_physical_out != NULL) {
1622bd670b35SErik Nordmark 		(void) net_event_shutdown(ipst->ips_arp_net_data,
1623bd670b35SErik Nordmark 		    &ipst->ips_arp_physical_out_event);
1624bd670b35SErik Nordmark 	}
1625bd670b35SErik Nordmark 	if (ipst->ips_arpnicevents != NULL) {
1626bd670b35SErik Nordmark 		(void) net_event_shutdown(ipst->ips_arp_net_data,
1627bd670b35SErik Nordmark 		    &ipst->ips_arp_nic_events);
1628bd670b35SErik Nordmark 	}
1629bd670b35SErik Nordmark }
1630bd670b35SErik Nordmark 
1631bd670b35SErik Nordmark /* netinfo routines for the unsupported cases */
1632bd670b35SErik Nordmark 
1633bd670b35SErik Nordmark /* ARGSUSED */
1634bd670b35SErik Nordmark int
net_no_getmtu(net_handle_t handle,phy_if_t phy_ifdata,lif_if_t ifdata)1635bd670b35SErik Nordmark net_no_getmtu(net_handle_t handle, phy_if_t phy_ifdata, lif_if_t ifdata)
1636bd670b35SErik Nordmark {
1637bd670b35SErik Nordmark 	return (-1);
1638bd670b35SErik Nordmark }
1639bd670b35SErik Nordmark 
1640bd670b35SErik Nordmark /* ARGSUSED */
1641bd670b35SErik Nordmark static int
net_no_getpmtuenabled(net_handle_t neti)1642bd670b35SErik Nordmark net_no_getpmtuenabled(net_handle_t neti)
1643bd670b35SErik Nordmark {
1644bd670b35SErik Nordmark 	return (-1);
1645bd670b35SErik Nordmark }
1646bd670b35SErik Nordmark 
1647bd670b35SErik Nordmark /* ARGSUSED */
1648bd670b35SErik Nordmark static lif_if_t
net_no_lifgetnext(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata)1649bd670b35SErik Nordmark net_no_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
1650bd670b35SErik Nordmark {
1651bd670b35SErik Nordmark 	return (-1);
1652bd670b35SErik Nordmark }
1653bd670b35SErik Nordmark 
1654bd670b35SErik Nordmark /* ARGSUSED */
1655bd670b35SErik Nordmark static int
net_no_inject(net_handle_t neti,inject_t style,net_inject_t * packet)1656bd670b35SErik Nordmark net_no_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
1657bd670b35SErik Nordmark {
1658bd670b35SErik Nordmark 	return (-1);
1659bd670b35SErik Nordmark }
1660bd670b35SErik Nordmark 
1661bd670b35SErik Nordmark /* ARGSUSED */
1662bd670b35SErik Nordmark static phy_if_t
net_no_routeto(net_handle_t neti,struct sockaddr * address,struct sockaddr * next)1663bd670b35SErik Nordmark net_no_routeto(net_handle_t neti, struct sockaddr *address,
1664bd670b35SErik Nordmark     struct sockaddr *next)
1665bd670b35SErik Nordmark {
1666bd670b35SErik Nordmark 	return ((phy_if_t)-1);
1667bd670b35SErik Nordmark }
1668bd670b35SErik Nordmark 
1669bd670b35SErik Nordmark /* ARGSUSED */
1670bd670b35SErik Nordmark static int
net_no_ispartialchecksum(net_handle_t neti,mblk_t * mp)1671bd670b35SErik Nordmark net_no_ispartialchecksum(net_handle_t neti, mblk_t *mp)
1672bd670b35SErik Nordmark {
1673bd670b35SErik Nordmark 	return (-1);
1674bd670b35SErik Nordmark }
1675bd670b35SErik Nordmark 
1676bd670b35SErik Nordmark /* ARGSUSED */
1677bd670b35SErik Nordmark static int
net_no_getlifaddr(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,size_t nelem,net_ifaddr_t type[],void * storage)1678bd670b35SErik Nordmark net_no_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1679bd670b35SErik Nordmark     size_t nelem, net_ifaddr_t type[], void *storage)
1680bd670b35SErik Nordmark {
1681bd670b35SErik Nordmark 	return (-1);
1682bd670b35SErik Nordmark }
1683bd670b35SErik Nordmark 
1684bd670b35SErik Nordmark /* ARGSUSED */
1685bd670b35SErik Nordmark static int
net_no_getlifzone(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,zoneid_t * zoneid)1686bd670b35SErik Nordmark net_no_getlifzone(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1687bd670b35SErik Nordmark     zoneid_t *zoneid)
1688bd670b35SErik Nordmark {
1689bd670b35SErik Nordmark 	return (-1);
1690bd670b35SErik Nordmark }
1691bd670b35SErik Nordmark 
1692bd670b35SErik Nordmark /* ARGSUSED */
1693bd670b35SErik Nordmark static int
net_no_getlifflags(net_handle_t neti,phy_if_t phy_ifdata,lif_if_t ifdata,uint64_t * flags)1694bd670b35SErik Nordmark net_no_getlifflags(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
1695bd670b35SErik Nordmark     uint64_t *flags)
1696bd670b35SErik Nordmark {
1697bd670b35SErik Nordmark 	return (-1);
1698bd670b35SErik Nordmark }
1699