1*10616SSebastien.Roy@Sun.COM /*
2*10616SSebastien.Roy@Sun.COM  * CDDL HEADER START
3*10616SSebastien.Roy@Sun.COM  *
4*10616SSebastien.Roy@Sun.COM  * The contents of this file are subject to the terms of the
5*10616SSebastien.Roy@Sun.COM  * Common Development and Distribution License (the "License").
6*10616SSebastien.Roy@Sun.COM  * You may not use this file except in compliance with the License.
7*10616SSebastien.Roy@Sun.COM  *
8*10616SSebastien.Roy@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10616SSebastien.Roy@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10616SSebastien.Roy@Sun.COM  * See the License for the specific language governing permissions
11*10616SSebastien.Roy@Sun.COM  * and limitations under the License.
12*10616SSebastien.Roy@Sun.COM  *
13*10616SSebastien.Roy@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10616SSebastien.Roy@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10616SSebastien.Roy@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10616SSebastien.Roy@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10616SSebastien.Roy@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10616SSebastien.Roy@Sun.COM  *
19*10616SSebastien.Roy@Sun.COM  * CDDL HEADER END
20*10616SSebastien.Roy@Sun.COM  */
21*10616SSebastien.Roy@Sun.COM /*
22*10616SSebastien.Roy@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10616SSebastien.Roy@Sun.COM  * Use is subject to license terms.
24*10616SSebastien.Roy@Sun.COM  */
25*10616SSebastien.Roy@Sun.COM 
26*10616SSebastien.Roy@Sun.COM #include <assert.h>
27*10616SSebastien.Roy@Sun.COM #include <stdio.h>
28*10616SSebastien.Roy@Sun.COM #include <errno.h>
29*10616SSebastien.Roy@Sun.COM #include <stdlib.h>
30*10616SSebastien.Roy@Sun.COM #include <unistd.h>
31*10616SSebastien.Roy@Sun.COM #include <sys/types.h>
32*10616SSebastien.Roy@Sun.COM #include <fcntl.h>
33*10616SSebastien.Roy@Sun.COM #include <stropts.h>
34*10616SSebastien.Roy@Sun.COM #include <string.h>
35*10616SSebastien.Roy@Sun.COM #include <netdb.h>
36*10616SSebastien.Roy@Sun.COM #include <sys/conf.h>
37*10616SSebastien.Roy@Sun.COM #include <sys/socket.h>
38*10616SSebastien.Roy@Sun.COM #include <netinet/in.h>
39*10616SSebastien.Roy@Sun.COM #include <inet/iptun.h>
40*10616SSebastien.Roy@Sun.COM #include <sys/dls.h>
41*10616SSebastien.Roy@Sun.COM #include <libdlpi.h>
42*10616SSebastien.Roy@Sun.COM #include <libdladm_impl.h>
43*10616SSebastien.Roy@Sun.COM #include <libdllink.h>
44*10616SSebastien.Roy@Sun.COM #include <libdliptun.h>
45*10616SSebastien.Roy@Sun.COM 
46*10616SSebastien.Roy@Sun.COM /*
47*10616SSebastien.Roy@Sun.COM  * IP Tunneling Administration Library.
48*10616SSebastien.Roy@Sun.COM  * This library is used by dladm(1M) and to configure IP tunnel links.
49*10616SSebastien.Roy@Sun.COM  */
50*10616SSebastien.Roy@Sun.COM 
51*10616SSebastien.Roy@Sun.COM #define	IPTUN_CONF_TYPE		"type"
52*10616SSebastien.Roy@Sun.COM #define	IPTUN_CONF_LADDR	"laddr"
53*10616SSebastien.Roy@Sun.COM #define	IPTUN_CONF_RADDR	"raddr"
54*10616SSebastien.Roy@Sun.COM 
55*10616SSebastien.Roy@Sun.COM /*
56*10616SSebastien.Roy@Sun.COM  * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't
57*10616SSebastien.Roy@Sun.COM  * loaded yet, the ioctls may return EAGAIN.  We try the ioctl
58*10616SSebastien.Roy@Sun.COM  * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL
59*10616SSebastien.Roy@Sun.COM  * microseconds between attempts.
60*10616SSebastien.Roy@Sun.COM  */
61*10616SSebastien.Roy@Sun.COM #define	IPTUN_IOCTL_ATTEMPT_LIMIT	3
62*10616SSebastien.Roy@Sun.COM #define	IPTUN_IOCTL_ATTEMPT_INTERVAL	10000
63*10616SSebastien.Roy@Sun.COM 
64*10616SSebastien.Roy@Sun.COM dladm_status_t
65*10616SSebastien.Roy@Sun.COM i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp)
66*10616SSebastien.Roy@Sun.COM {
67*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
68*10616SSebastien.Roy@Sun.COM 	uint_t		attempt;
69*10616SSebastien.Roy@Sun.COM 
70*10616SSebastien.Roy@Sun.COM 	for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) {
71*10616SSebastien.Roy@Sun.COM 		if (attempt != 0)
72*10616SSebastien.Roy@Sun.COM 			(void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL);
73*10616SSebastien.Roy@Sun.COM 		status = (ioctl(dladm_dld_fd(handle), cmd, dp) == 0) ?
74*10616SSebastien.Roy@Sun.COM 		    DLADM_STATUS_OK : dladm_errno2status(errno);
75*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_TRYAGAIN)
76*10616SSebastien.Roy@Sun.COM 			break;
77*10616SSebastien.Roy@Sun.COM 	}
78*10616SSebastien.Roy@Sun.COM 	return (status);
79*10616SSebastien.Roy@Sun.COM }
80*10616SSebastien.Roy@Sun.COM 
81*10616SSebastien.Roy@Sun.COM /*
82*10616SSebastien.Roy@Sun.COM  * Given tunnel paramaters as supplied by a library consumer, fill in kernel
83*10616SSebastien.Roy@Sun.COM  * parameters to be passed down to the iptun control device.
84*10616SSebastien.Roy@Sun.COM  */
85*10616SSebastien.Roy@Sun.COM static dladm_status_t
86*10616SSebastien.Roy@Sun.COM i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params,
87*10616SSebastien.Roy@Sun.COM     iptun_kparams_t *ik)
88*10616SSebastien.Roy@Sun.COM {
89*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
90*10616SSebastien.Roy@Sun.COM 	struct addrinfo	*ai, hints;
91*10616SSebastien.Roy@Sun.COM 	iptun_kparams_t	tmpik;
92*10616SSebastien.Roy@Sun.COM 	iptun_type_t	iptuntype = IPTUN_TYPE_UNKNOWN;
93*10616SSebastien.Roy@Sun.COM 
94*10616SSebastien.Roy@Sun.COM 	(void) memset(ik, 0, sizeof (*ik));
95*10616SSebastien.Roy@Sun.COM 
96*10616SSebastien.Roy@Sun.COM 	ik->iptun_kparam_linkid = params->iptun_param_linkid;
97*10616SSebastien.Roy@Sun.COM 
98*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_TYPE) {
99*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_type = iptuntype = params->iptun_param_type;
100*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_flags |= IPTUN_KPARAM_TYPE;
101*10616SSebastien.Roy@Sun.COM 	}
102*10616SSebastien.Roy@Sun.COM 
103*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) {
104*10616SSebastien.Roy@Sun.COM 		if (iptuntype == IPTUN_TYPE_UNKNOWN) {
105*10616SSebastien.Roy@Sun.COM 			/*
106*10616SSebastien.Roy@Sun.COM 			 * We need to get the type of this existing tunnel in
107*10616SSebastien.Roy@Sun.COM 			 * order to validate and/or look up the right kind of
108*10616SSebastien.Roy@Sun.COM 			 * IP address.
109*10616SSebastien.Roy@Sun.COM 			 */
110*10616SSebastien.Roy@Sun.COM 			tmpik.iptun_kparam_linkid = params->iptun_param_linkid;
111*10616SSebastien.Roy@Sun.COM 			status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik);
112*10616SSebastien.Roy@Sun.COM 			if (status != DLADM_STATUS_OK)
113*10616SSebastien.Roy@Sun.COM 				return (status);
114*10616SSebastien.Roy@Sun.COM 			iptuntype = tmpik.iptun_kparam_type;
115*10616SSebastien.Roy@Sun.COM 		}
116*10616SSebastien.Roy@Sun.COM 
117*10616SSebastien.Roy@Sun.COM 		(void) memset(&hints, 0, sizeof (hints));
118*10616SSebastien.Roy@Sun.COM 		switch (iptuntype) {
119*10616SSebastien.Roy@Sun.COM 		case IPTUN_TYPE_IPV4:
120*10616SSebastien.Roy@Sun.COM 		case IPTUN_TYPE_6TO4:
121*10616SSebastien.Roy@Sun.COM 			hints.ai_family = AF_INET;
122*10616SSebastien.Roy@Sun.COM 			break;
123*10616SSebastien.Roy@Sun.COM 		case IPTUN_TYPE_IPV6:
124*10616SSebastien.Roy@Sun.COM 			hints.ai_family = AF_INET6;
125*10616SSebastien.Roy@Sun.COM 			break;
126*10616SSebastien.Roy@Sun.COM 		}
127*10616SSebastien.Roy@Sun.COM 	}
128*10616SSebastien.Roy@Sun.COM 
129*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
130*10616SSebastien.Roy@Sun.COM 		if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) !=
131*10616SSebastien.Roy@Sun.COM 		    0)
132*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNLADDR);
133*10616SSebastien.Roy@Sun.COM 		if (ai->ai_next != NULL) {
134*10616SSebastien.Roy@Sun.COM 			freeaddrinfo(ai);
135*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNLADDR);
136*10616SSebastien.Roy@Sun.COM 		}
137*10616SSebastien.Roy@Sun.COM 		(void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr,
138*10616SSebastien.Roy@Sun.COM 		    ai->ai_addrlen);
139*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR;
140*10616SSebastien.Roy@Sun.COM 		freeaddrinfo(ai);
141*10616SSebastien.Roy@Sun.COM 	}
142*10616SSebastien.Roy@Sun.COM 
143*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
144*10616SSebastien.Roy@Sun.COM 		if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) !=
145*10616SSebastien.Roy@Sun.COM 		    0)
146*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNRADDR);
147*10616SSebastien.Roy@Sun.COM 		if (ai->ai_next != NULL) {
148*10616SSebastien.Roy@Sun.COM 			freeaddrinfo(ai);
149*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNRADDR);
150*10616SSebastien.Roy@Sun.COM 		}
151*10616SSebastien.Roy@Sun.COM 		(void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr,
152*10616SSebastien.Roy@Sun.COM 		    ai->ai_addrlen);
153*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR;
154*10616SSebastien.Roy@Sun.COM 		freeaddrinfo(ai);
155*10616SSebastien.Roy@Sun.COM 	}
156*10616SSebastien.Roy@Sun.COM 
157*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) {
158*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_secinfo = params->iptun_param_secinfo;
159*10616SSebastien.Roy@Sun.COM 		ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO;
160*10616SSebastien.Roy@Sun.COM 	}
161*10616SSebastien.Roy@Sun.COM 
162*10616SSebastien.Roy@Sun.COM 	return (DLADM_STATUS_OK);
163*10616SSebastien.Roy@Sun.COM }
164*10616SSebastien.Roy@Sun.COM 
165*10616SSebastien.Roy@Sun.COM /*
166*10616SSebastien.Roy@Sun.COM  * The inverse of i_iptun_kparams().  Given kernel tunnel paramaters as
167*10616SSebastien.Roy@Sun.COM  * returned from an IPTUN_INFO ioctl, fill in tunnel parameters.
168*10616SSebastien.Roy@Sun.COM  */
169*10616SSebastien.Roy@Sun.COM static dladm_status_t
170*10616SSebastien.Roy@Sun.COM i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params)
171*10616SSebastien.Roy@Sun.COM {
172*10616SSebastien.Roy@Sun.COM 	socklen_t salen;
173*10616SSebastien.Roy@Sun.COM 
174*10616SSebastien.Roy@Sun.COM 	(void) memset(params, 0, sizeof (*params));
175*10616SSebastien.Roy@Sun.COM 
176*10616SSebastien.Roy@Sun.COM 	params->iptun_param_linkid = ik->iptun_kparam_linkid;
177*10616SSebastien.Roy@Sun.COM 
178*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) {
179*10616SSebastien.Roy@Sun.COM 		params->iptun_param_type = ik->iptun_kparam_type;
180*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_TYPE;
181*10616SSebastien.Roy@Sun.COM 	}
182*10616SSebastien.Roy@Sun.COM 
183*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) {
184*10616SSebastien.Roy@Sun.COM 		salen = ik->iptun_kparam_laddr.ss_family == AF_INET ?
185*10616SSebastien.Roy@Sun.COM 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
186*10616SSebastien.Roy@Sun.COM 		if (getnameinfo((const struct sockaddr *)
187*10616SSebastien.Roy@Sun.COM 		    &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr,
188*10616SSebastien.Roy@Sun.COM 		    sizeof (params->iptun_param_laddr), NULL, 0,
189*10616SSebastien.Roy@Sun.COM 		    NI_NUMERICHOST) != 0) {
190*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNLADDR);
191*10616SSebastien.Roy@Sun.COM 		}
192*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
193*10616SSebastien.Roy@Sun.COM 	}
194*10616SSebastien.Roy@Sun.COM 
195*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) {
196*10616SSebastien.Roy@Sun.COM 		salen = ik->iptun_kparam_raddr.ss_family == AF_INET ?
197*10616SSebastien.Roy@Sun.COM 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
198*10616SSebastien.Roy@Sun.COM 		if (getnameinfo((const struct sockaddr *)
199*10616SSebastien.Roy@Sun.COM 		    &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr,
200*10616SSebastien.Roy@Sun.COM 		    sizeof (params->iptun_param_raddr), NULL, 0,
201*10616SSebastien.Roy@Sun.COM 		    NI_NUMERICHOST) != 0) {
202*10616SSebastien.Roy@Sun.COM 			return (DLADM_STATUS_BADIPTUNRADDR);
203*10616SSebastien.Roy@Sun.COM 		}
204*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
205*10616SSebastien.Roy@Sun.COM 	}
206*10616SSebastien.Roy@Sun.COM 
207*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) {
208*10616SSebastien.Roy@Sun.COM 		params->iptun_param_secinfo = ik->iptun_kparam_secinfo;
209*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_SECINFO;
210*10616SSebastien.Roy@Sun.COM 	}
211*10616SSebastien.Roy@Sun.COM 
212*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT)
213*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT;
214*10616SSebastien.Roy@Sun.COM 
215*10616SSebastien.Roy@Sun.COM 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL)
216*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL;
217*10616SSebastien.Roy@Sun.COM 
218*10616SSebastien.Roy@Sun.COM 	return (DLADM_STATUS_OK);
219*10616SSebastien.Roy@Sun.COM }
220*10616SSebastien.Roy@Sun.COM 
221*10616SSebastien.Roy@Sun.COM dladm_status_t
222*10616SSebastien.Roy@Sun.COM i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params)
223*10616SSebastien.Roy@Sun.COM {
224*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
225*10616SSebastien.Roy@Sun.COM 	iptun_kparams_t	ik;
226*10616SSebastien.Roy@Sun.COM 
227*10616SSebastien.Roy@Sun.COM 	ik.iptun_kparam_linkid = params->iptun_param_linkid;
228*10616SSebastien.Roy@Sun.COM 	status = i_iptun_ioctl(handle, IPTUN_INFO, &ik);
229*10616SSebastien.Roy@Sun.COM 	if (status == DLADM_STATUS_OK)
230*10616SSebastien.Roy@Sun.COM 		status = i_iptun_params(&ik, params);
231*10616SSebastien.Roy@Sun.COM 	return (status);
232*10616SSebastien.Roy@Sun.COM }
233*10616SSebastien.Roy@Sun.COM 
234*10616SSebastien.Roy@Sun.COM /*
235*10616SSebastien.Roy@Sun.COM  * Read tunnel parameters from persistent storage.  Note that the tunnel type
236*10616SSebastien.Roy@Sun.COM  * is the only thing which must always be in the configuratioh.  All other
237*10616SSebastien.Roy@Sun.COM  * parameters (currently the source and destination addresses) may or may not
238*10616SSebastien.Roy@Sun.COM  * have been configured, and therefore may not have been set.
239*10616SSebastien.Roy@Sun.COM  */
240*10616SSebastien.Roy@Sun.COM static dladm_status_t
241*10616SSebastien.Roy@Sun.COM i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params)
242*10616SSebastien.Roy@Sun.COM {
243*10616SSebastien.Roy@Sun.COM 	dladm_status_t		status;
244*10616SSebastien.Roy@Sun.COM 	dladm_conf_t		conf;
245*10616SSebastien.Roy@Sun.COM 	datalink_class_t	class;
246*10616SSebastien.Roy@Sun.COM 	uint64_t		temp;
247*10616SSebastien.Roy@Sun.COM 
248*10616SSebastien.Roy@Sun.COM 	/* First, make sure that this is an IP tunnel. */
249*10616SSebastien.Roy@Sun.COM 	if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid,
250*10616SSebastien.Roy@Sun.COM 	    NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK)
251*10616SSebastien.Roy@Sun.COM 		return (status);
252*10616SSebastien.Roy@Sun.COM 	if (class != DATALINK_CLASS_IPTUN)
253*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_LINKINVAL);
254*10616SSebastien.Roy@Sun.COM 
255*10616SSebastien.Roy@Sun.COM 	status = dladm_read_conf(handle, params->iptun_param_linkid, &conf);
256*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
257*10616SSebastien.Roy@Sun.COM 		return (status);
258*10616SSebastien.Roy@Sun.COM 
259*10616SSebastien.Roy@Sun.COM 	params->iptun_param_flags = 0;
260*10616SSebastien.Roy@Sun.COM 
261*10616SSebastien.Roy@Sun.COM 	if ((status = dladm_get_conf_field(handle, conf, IPTUN_CONF_TYPE, &temp,
262*10616SSebastien.Roy@Sun.COM 	    sizeof (temp))) != DLADM_STATUS_OK)
263*10616SSebastien.Roy@Sun.COM 		goto done;
264*10616SSebastien.Roy@Sun.COM 	params->iptun_param_type = (iptun_type_t)temp;
265*10616SSebastien.Roy@Sun.COM 	params->iptun_param_flags |= IPTUN_PARAM_TYPE;
266*10616SSebastien.Roy@Sun.COM 
267*10616SSebastien.Roy@Sun.COM 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_LADDR,
268*10616SSebastien.Roy@Sun.COM 	    params->iptun_param_laddr, sizeof (params->iptun_param_laddr)) ==
269*10616SSebastien.Roy@Sun.COM 	    DLADM_STATUS_OK)
270*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
271*10616SSebastien.Roy@Sun.COM 
272*10616SSebastien.Roy@Sun.COM 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_RADDR,
273*10616SSebastien.Roy@Sun.COM 	    params->iptun_param_raddr, sizeof (params->iptun_param_raddr)) ==
274*10616SSebastien.Roy@Sun.COM 	    DLADM_STATUS_OK)
275*10616SSebastien.Roy@Sun.COM 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
276*10616SSebastien.Roy@Sun.COM 
277*10616SSebastien.Roy@Sun.COM done:
278*10616SSebastien.Roy@Sun.COM 	dladm_destroy_conf(handle, conf);
279*10616SSebastien.Roy@Sun.COM 	return (status);
280*10616SSebastien.Roy@Sun.COM }
281*10616SSebastien.Roy@Sun.COM 
282*10616SSebastien.Roy@Sun.COM static dladm_status_t
283*10616SSebastien.Roy@Sun.COM i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params)
284*10616SSebastien.Roy@Sun.COM {
285*10616SSebastien.Roy@Sun.COM 	iptun_kparams_t	ik;
286*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
287*10616SSebastien.Roy@Sun.COM 
288*10616SSebastien.Roy@Sun.COM 	/* The tunnel type is required for creation. */
289*10616SSebastien.Roy@Sun.COM 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
290*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_IPTUNTYPEREQD);
291*10616SSebastien.Roy@Sun.COM 
292*10616SSebastien.Roy@Sun.COM 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
293*10616SSebastien.Roy@Sun.COM 		status = i_iptun_ioctl(handle, IPTUN_CREATE, &ik);
294*10616SSebastien.Roy@Sun.COM 	return (status);
295*10616SSebastien.Roy@Sun.COM }
296*10616SSebastien.Roy@Sun.COM 
297*10616SSebastien.Roy@Sun.COM static dladm_status_t
298*10616SSebastien.Roy@Sun.COM i_iptun_create_db(dladm_handle_t handle, const char *name,
299*10616SSebastien.Roy@Sun.COM     iptun_params_t *params, uint32_t media)
300*10616SSebastien.Roy@Sun.COM {
301*10616SSebastien.Roy@Sun.COM 	dladm_conf_t	conf;
302*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
303*10616SSebastien.Roy@Sun.COM 	uint64_t	storage;
304*10616SSebastien.Roy@Sun.COM 
305*10616SSebastien.Roy@Sun.COM 	status = dladm_create_conf(handle, name, params->iptun_param_linkid,
306*10616SSebastien.Roy@Sun.COM 	    DATALINK_CLASS_IPTUN, media, &conf);
307*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
308*10616SSebastien.Roy@Sun.COM 		return (status);
309*10616SSebastien.Roy@Sun.COM 
310*10616SSebastien.Roy@Sun.COM 	assert(params->iptun_param_flags & IPTUN_PARAM_TYPE);
311*10616SSebastien.Roy@Sun.COM 	storage = params->iptun_param_type;
312*10616SSebastien.Roy@Sun.COM 	status = dladm_set_conf_field(handle, conf, IPTUN_CONF_TYPE,
313*10616SSebastien.Roy@Sun.COM 	    DLADM_TYPE_UINT64, &storage);
314*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
315*10616SSebastien.Roy@Sun.COM 		goto done;
316*10616SSebastien.Roy@Sun.COM 
317*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
318*10616SSebastien.Roy@Sun.COM 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
319*10616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, params->iptun_param_laddr);
320*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
321*10616SSebastien.Roy@Sun.COM 			goto done;
322*10616SSebastien.Roy@Sun.COM 	}
323*10616SSebastien.Roy@Sun.COM 
324*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
325*10616SSebastien.Roy@Sun.COM 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
326*10616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, params->iptun_param_raddr);
327*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
328*10616SSebastien.Roy@Sun.COM 			goto done;
329*10616SSebastien.Roy@Sun.COM 	}
330*10616SSebastien.Roy@Sun.COM 
331*10616SSebastien.Roy@Sun.COM 	status = dladm_write_conf(handle, conf);
332*10616SSebastien.Roy@Sun.COM 
333*10616SSebastien.Roy@Sun.COM done:
334*10616SSebastien.Roy@Sun.COM 	dladm_destroy_conf(handle, conf);
335*10616SSebastien.Roy@Sun.COM 	return (status);
336*10616SSebastien.Roy@Sun.COM }
337*10616SSebastien.Roy@Sun.COM 
338*10616SSebastien.Roy@Sun.COM static dladm_status_t
339*10616SSebastien.Roy@Sun.COM i_iptun_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
340*10616SSebastien.Roy@Sun.COM {
341*10616SSebastien.Roy@Sun.COM 	dladm_status_t status;
342*10616SSebastien.Roy@Sun.COM 
343*10616SSebastien.Roy@Sun.COM 	status = i_iptun_ioctl(handle, IPTUN_DELETE, &linkid);
344*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
345*10616SSebastien.Roy@Sun.COM 		return (status);
346*10616SSebastien.Roy@Sun.COM 	(void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE);
347*10616SSebastien.Roy@Sun.COM 	return (DLADM_STATUS_OK);
348*10616SSebastien.Roy@Sun.COM }
349*10616SSebastien.Roy@Sun.COM 
350*10616SSebastien.Roy@Sun.COM static dladm_status_t
351*10616SSebastien.Roy@Sun.COM i_iptun_modify_sys(dladm_handle_t handle, const iptun_params_t *params)
352*10616SSebastien.Roy@Sun.COM {
353*10616SSebastien.Roy@Sun.COM 	iptun_kparams_t	ik;
354*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
355*10616SSebastien.Roy@Sun.COM 
356*10616SSebastien.Roy@Sun.COM 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
357*10616SSebastien.Roy@Sun.COM 		status = i_iptun_ioctl(handle, IPTUN_MODIFY, &ik);
358*10616SSebastien.Roy@Sun.COM 	return (status);
359*10616SSebastien.Roy@Sun.COM }
360*10616SSebastien.Roy@Sun.COM 
361*10616SSebastien.Roy@Sun.COM static dladm_status_t
362*10616SSebastien.Roy@Sun.COM i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params)
363*10616SSebastien.Roy@Sun.COM {
364*10616SSebastien.Roy@Sun.COM 	dladm_conf_t	conf;
365*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
366*10616SSebastien.Roy@Sun.COM 
367*10616SSebastien.Roy@Sun.COM 	assert(params->iptun_param_flags &
368*10616SSebastien.Roy@Sun.COM 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR));
369*10616SSebastien.Roy@Sun.COM 
370*10616SSebastien.Roy@Sun.COM 	/*
371*10616SSebastien.Roy@Sun.COM 	 * The only parameters that can be modified persistently are the local
372*10616SSebastien.Roy@Sun.COM 	 * and remote addresses.
373*10616SSebastien.Roy@Sun.COM 	 */
374*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & ~(IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR))
375*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_BADARG);
376*10616SSebastien.Roy@Sun.COM 
377*10616SSebastien.Roy@Sun.COM 	status = dladm_read_conf(handle, params->iptun_param_linkid, &conf);
378*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
379*10616SSebastien.Roy@Sun.COM 		return (status);
380*10616SSebastien.Roy@Sun.COM 
381*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
382*10616SSebastien.Roy@Sun.COM 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
383*10616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, (void *)params->iptun_param_laddr);
384*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
385*10616SSebastien.Roy@Sun.COM 			goto done;
386*10616SSebastien.Roy@Sun.COM 	}
387*10616SSebastien.Roy@Sun.COM 
388*10616SSebastien.Roy@Sun.COM 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
389*10616SSebastien.Roy@Sun.COM 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
390*10616SSebastien.Roy@Sun.COM 		    DLADM_TYPE_STR, (void *)params->iptun_param_raddr);
391*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
392*10616SSebastien.Roy@Sun.COM 			goto done;
393*10616SSebastien.Roy@Sun.COM 	}
394*10616SSebastien.Roy@Sun.COM 
395*10616SSebastien.Roy@Sun.COM 	status = dladm_write_conf(handle, conf);
396*10616SSebastien.Roy@Sun.COM 
397*10616SSebastien.Roy@Sun.COM done:
398*10616SSebastien.Roy@Sun.COM 	dladm_destroy_conf(handle, conf);
399*10616SSebastien.Roy@Sun.COM 	return (status);
400*10616SSebastien.Roy@Sun.COM }
401*10616SSebastien.Roy@Sun.COM 
402*10616SSebastien.Roy@Sun.COM dladm_status_t
403*10616SSebastien.Roy@Sun.COM dladm_iptun_create(dladm_handle_t handle, const char *name,
404*10616SSebastien.Roy@Sun.COM     iptun_params_t *params, uint32_t flags)
405*10616SSebastien.Roy@Sun.COM {
406*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
407*10616SSebastien.Roy@Sun.COM 	uint32_t	linkmgmt_flags = flags;
408*10616SSebastien.Roy@Sun.COM 	uint32_t	media;
409*10616SSebastien.Roy@Sun.COM 
410*10616SSebastien.Roy@Sun.COM 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
411*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_IPTUNTYPEREQD);
412*10616SSebastien.Roy@Sun.COM 
413*10616SSebastien.Roy@Sun.COM 	switch (params->iptun_param_type) {
414*10616SSebastien.Roy@Sun.COM 	case IPTUN_TYPE_IPV4:
415*10616SSebastien.Roy@Sun.COM 		media = DL_IPV4;
416*10616SSebastien.Roy@Sun.COM 		break;
417*10616SSebastien.Roy@Sun.COM 	case IPTUN_TYPE_IPV6:
418*10616SSebastien.Roy@Sun.COM 		media = DL_IPV6;
419*10616SSebastien.Roy@Sun.COM 		break;
420*10616SSebastien.Roy@Sun.COM 	case IPTUN_TYPE_6TO4:
421*10616SSebastien.Roy@Sun.COM 		media = DL_6TO4;
422*10616SSebastien.Roy@Sun.COM 		break;
423*10616SSebastien.Roy@Sun.COM 	default:
424*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_IPTUNTYPE);
425*10616SSebastien.Roy@Sun.COM 	}
426*10616SSebastien.Roy@Sun.COM 
427*10616SSebastien.Roy@Sun.COM 	status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN,
428*10616SSebastien.Roy@Sun.COM 	    media, linkmgmt_flags, &params->iptun_param_linkid);
429*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
430*10616SSebastien.Roy@Sun.COM 		return (status);
431*10616SSebastien.Roy@Sun.COM 
432*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
433*10616SSebastien.Roy@Sun.COM 		status = i_iptun_create_db(handle, name, params, media);
434*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
435*10616SSebastien.Roy@Sun.COM 			goto done;
436*10616SSebastien.Roy@Sun.COM 	}
437*10616SSebastien.Roy@Sun.COM 
438*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
439*10616SSebastien.Roy@Sun.COM 		status = i_iptun_create_sys(handle, params);
440*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
441*10616SSebastien.Roy@Sun.COM 			(void) dladm_remove_conf(handle,
442*10616SSebastien.Roy@Sun.COM 			    params->iptun_param_linkid);
443*10616SSebastien.Roy@Sun.COM 		}
444*10616SSebastien.Roy@Sun.COM 	}
445*10616SSebastien.Roy@Sun.COM 
446*10616SSebastien.Roy@Sun.COM done:
447*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK) {
448*10616SSebastien.Roy@Sun.COM 		(void) dladm_destroy_datalink_id(handle,
449*10616SSebastien.Roy@Sun.COM 		    params->iptun_param_linkid, flags);
450*10616SSebastien.Roy@Sun.COM 	}
451*10616SSebastien.Roy@Sun.COM 	return (status);
452*10616SSebastien.Roy@Sun.COM }
453*10616SSebastien.Roy@Sun.COM 
454*10616SSebastien.Roy@Sun.COM dladm_status_t
455*10616SSebastien.Roy@Sun.COM dladm_iptun_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
456*10616SSebastien.Roy@Sun.COM {
457*10616SSebastien.Roy@Sun.COM 	dladm_status_t		status;
458*10616SSebastien.Roy@Sun.COM 	datalink_class_t	class;
459*10616SSebastien.Roy@Sun.COM 
460*10616SSebastien.Roy@Sun.COM 	/* First, make sure that this is an IP tunnel. */
461*10616SSebastien.Roy@Sun.COM 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
462*10616SSebastien.Roy@Sun.COM 	    NULL, 0)) != DLADM_STATUS_OK)
463*10616SSebastien.Roy@Sun.COM 		return (status);
464*10616SSebastien.Roy@Sun.COM 	if (class != DATALINK_CLASS_IPTUN)
465*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_LINKINVAL);
466*10616SSebastien.Roy@Sun.COM 
467*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
468*10616SSebastien.Roy@Sun.COM 		/*
469*10616SSebastien.Roy@Sun.COM 		 * Note that if i_iptun_delete_sys() fails with
470*10616SSebastien.Roy@Sun.COM 		 * DLADM_STATUS_NOTFOUND and the caller also wishes to delete
471*10616SSebastien.Roy@Sun.COM 		 * the persistent configuration, we still fall through to the
472*10616SSebastien.Roy@Sun.COM 		 * DLADM_OPT_PERSIST case in case the tunnel only exists
473*10616SSebastien.Roy@Sun.COM 		 * persistently.
474*10616SSebastien.Roy@Sun.COM 		 */
475*10616SSebastien.Roy@Sun.COM 		status = i_iptun_delete_sys(handle, linkid);
476*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK &&
477*10616SSebastien.Roy@Sun.COM 		    (status != DLADM_STATUS_NOTFOUND ||
478*10616SSebastien.Roy@Sun.COM 		    !(flags & DLADM_OPT_PERSIST)))
479*10616SSebastien.Roy@Sun.COM 			return (status);
480*10616SSebastien.Roy@Sun.COM 	}
481*10616SSebastien.Roy@Sun.COM 
482*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
483*10616SSebastien.Roy@Sun.COM 		(void) dladm_remove_conf(handle, linkid);
484*10616SSebastien.Roy@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
485*10616SSebastien.Roy@Sun.COM 		    DLADM_OPT_PERSIST);
486*10616SSebastien.Roy@Sun.COM 	}
487*10616SSebastien.Roy@Sun.COM 	return (DLADM_STATUS_OK);
488*10616SSebastien.Roy@Sun.COM }
489*10616SSebastien.Roy@Sun.COM 
490*10616SSebastien.Roy@Sun.COM dladm_status_t
491*10616SSebastien.Roy@Sun.COM dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params,
492*10616SSebastien.Roy@Sun.COM     uint32_t flags)
493*10616SSebastien.Roy@Sun.COM {
494*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
495*10616SSebastien.Roy@Sun.COM 	iptun_params_t	old_params;
496*10616SSebastien.Roy@Sun.COM 
497*10616SSebastien.Roy@Sun.COM 	/*
498*10616SSebastien.Roy@Sun.COM 	 * We can only modify the tunnel source, tunnel destination, or IPsec
499*10616SSebastien.Roy@Sun.COM 	 * policy.
500*10616SSebastien.Roy@Sun.COM 	 */
501*10616SSebastien.Roy@Sun.COM 	if (!(params->iptun_param_flags &
502*10616SSebastien.Roy@Sun.COM 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR|IPTUN_PARAM_SECINFO)))
503*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_BADARG);
504*10616SSebastien.Roy@Sun.COM 
505*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
506*10616SSebastien.Roy@Sun.COM 		/*
507*10616SSebastien.Roy@Sun.COM 		 * Before we change the database, save the old configuration
508*10616SSebastien.Roy@Sun.COM 		 * so that we can revert back if an error occurs.
509*10616SSebastien.Roy@Sun.COM 		 */
510*10616SSebastien.Roy@Sun.COM 		old_params.iptun_param_linkid = params->iptun_param_linkid;
511*10616SSebastien.Roy@Sun.COM 		status = i_iptun_get_dbparams(handle, &old_params);
512*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
513*10616SSebastien.Roy@Sun.COM 			return (status);
514*10616SSebastien.Roy@Sun.COM 		/* we'll only need to revert the parameters being modified */
515*10616SSebastien.Roy@Sun.COM 		old_params.iptun_param_flags = params->iptun_param_flags;
516*10616SSebastien.Roy@Sun.COM 
517*10616SSebastien.Roy@Sun.COM 		status = i_iptun_modify_db(handle, params);
518*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK)
519*10616SSebastien.Roy@Sun.COM 			return (status);
520*10616SSebastien.Roy@Sun.COM 	}
521*10616SSebastien.Roy@Sun.COM 
522*10616SSebastien.Roy@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
523*10616SSebastien.Roy@Sun.COM 		status = i_iptun_modify_sys(handle, params);
524*10616SSebastien.Roy@Sun.COM 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
525*10616SSebastien.Roy@Sun.COM 			(void) i_iptun_modify_db(handle, &old_params);
526*10616SSebastien.Roy@Sun.COM 		}
527*10616SSebastien.Roy@Sun.COM 	}
528*10616SSebastien.Roy@Sun.COM 
529*10616SSebastien.Roy@Sun.COM 	return (status);
530*10616SSebastien.Roy@Sun.COM }
531*10616SSebastien.Roy@Sun.COM 
532*10616SSebastien.Roy@Sun.COM dladm_status_t
533*10616SSebastien.Roy@Sun.COM dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params,
534*10616SSebastien.Roy@Sun.COM     uint32_t flags)
535*10616SSebastien.Roy@Sun.COM {
536*10616SSebastien.Roy@Sun.COM 	if (flags == DLADM_OPT_ACTIVE)
537*10616SSebastien.Roy@Sun.COM 		return (i_iptun_get_sysparams(handle, params));
538*10616SSebastien.Roy@Sun.COM 	else if (flags == DLADM_OPT_PERSIST)
539*10616SSebastien.Roy@Sun.COM 		return (i_iptun_get_dbparams(handle, params));
540*10616SSebastien.Roy@Sun.COM 	else
541*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_BADARG);
542*10616SSebastien.Roy@Sun.COM }
543*10616SSebastien.Roy@Sun.COM 
544*10616SSebastien.Roy@Sun.COM static int
545*10616SSebastien.Roy@Sun.COM i_iptun_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
546*10616SSebastien.Roy@Sun.COM {
547*10616SSebastien.Roy@Sun.COM 	dladm_status_t	*statusp = arg;
548*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
549*10616SSebastien.Roy@Sun.COM 	iptun_params_t	params;
550*10616SSebastien.Roy@Sun.COM 	boolean_t	id_up = B_FALSE;
551*10616SSebastien.Roy@Sun.COM 
552*10616SSebastien.Roy@Sun.COM 	status = dladm_up_datalink_id(handle, linkid);
553*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK)
554*10616SSebastien.Roy@Sun.COM 		goto done;
555*10616SSebastien.Roy@Sun.COM 	id_up = B_TRUE;
556*10616SSebastien.Roy@Sun.COM 
557*10616SSebastien.Roy@Sun.COM 	(void) memset(&params, 0, sizeof (params));
558*10616SSebastien.Roy@Sun.COM 
559*10616SSebastien.Roy@Sun.COM 	params.iptun_param_linkid = linkid;
560*10616SSebastien.Roy@Sun.COM 	if ((status = i_iptun_get_dbparams(handle, &params)) == DLADM_STATUS_OK)
561*10616SSebastien.Roy@Sun.COM 		status = i_iptun_create_sys(handle, &params);
562*10616SSebastien.Roy@Sun.COM done:
563*10616SSebastien.Roy@Sun.COM 	if (statusp != NULL)
564*10616SSebastien.Roy@Sun.COM 		*statusp = status;
565*10616SSebastien.Roy@Sun.COM 	if (status != DLADM_STATUS_OK && id_up) {
566*10616SSebastien.Roy@Sun.COM 		(void) dladm_destroy_datalink_id(handle, linkid,
567*10616SSebastien.Roy@Sun.COM 		    DLADM_OPT_ACTIVE);
568*10616SSebastien.Roy@Sun.COM 	}
569*10616SSebastien.Roy@Sun.COM 	return (DLADM_WALK_CONTINUE);
570*10616SSebastien.Roy@Sun.COM }
571*10616SSebastien.Roy@Sun.COM 
572*10616SSebastien.Roy@Sun.COM static int
573*10616SSebastien.Roy@Sun.COM i_iptun_down(dladm_handle_t handle, datalink_id_t linkid, void *arg)
574*10616SSebastien.Roy@Sun.COM {
575*10616SSebastien.Roy@Sun.COM 	dladm_status_t	*statusp = arg;
576*10616SSebastien.Roy@Sun.COM 	dladm_status_t	status;
577*10616SSebastien.Roy@Sun.COM 
578*10616SSebastien.Roy@Sun.COM 	status = i_iptun_delete_sys(handle, linkid);
579*10616SSebastien.Roy@Sun.COM 	if (statusp != NULL)
580*10616SSebastien.Roy@Sun.COM 		*statusp = status;
581*10616SSebastien.Roy@Sun.COM 	return (DLADM_WALK_CONTINUE);
582*10616SSebastien.Roy@Sun.COM }
583*10616SSebastien.Roy@Sun.COM 
584*10616SSebastien.Roy@Sun.COM /* ARGSUSED */
585*10616SSebastien.Roy@Sun.COM dladm_status_t
586*10616SSebastien.Roy@Sun.COM dladm_iptun_up(dladm_handle_t handle, datalink_id_t linkid)
587*10616SSebastien.Roy@Sun.COM {
588*10616SSebastien.Roy@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
589*10616SSebastien.Roy@Sun.COM 
590*10616SSebastien.Roy@Sun.COM 	if (linkid == DATALINK_ALL_LINKID) {
591*10616SSebastien.Roy@Sun.COM 		(void) dladm_walk_datalink_id(i_iptun_up, handle, NULL,
592*10616SSebastien.Roy@Sun.COM 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
593*10616SSebastien.Roy@Sun.COM 		    DLADM_OPT_PERSIST);
594*10616SSebastien.Roy@Sun.COM 	} else {
595*10616SSebastien.Roy@Sun.COM 		(void) i_iptun_up(handle, linkid, &status);
596*10616SSebastien.Roy@Sun.COM 	}
597*10616SSebastien.Roy@Sun.COM 	return (status);
598*10616SSebastien.Roy@Sun.COM }
599*10616SSebastien.Roy@Sun.COM 
600*10616SSebastien.Roy@Sun.COM dladm_status_t
601*10616SSebastien.Roy@Sun.COM dladm_iptun_down(dladm_handle_t handle, datalink_id_t linkid)
602*10616SSebastien.Roy@Sun.COM {
603*10616SSebastien.Roy@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
604*10616SSebastien.Roy@Sun.COM 
605*10616SSebastien.Roy@Sun.COM 	if (linkid == DATALINK_ALL_LINKID) {
606*10616SSebastien.Roy@Sun.COM 		(void) dladm_walk_datalink_id(i_iptun_down, handle, NULL,
607*10616SSebastien.Roy@Sun.COM 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
608*10616SSebastien.Roy@Sun.COM 		    DLADM_OPT_ACTIVE);
609*10616SSebastien.Roy@Sun.COM 	} else {
610*10616SSebastien.Roy@Sun.COM 		(void) i_iptun_down(handle, linkid, &status);
611*10616SSebastien.Roy@Sun.COM 	}
612*10616SSebastien.Roy@Sun.COM 	return (status);
613*10616SSebastien.Roy@Sun.COM }
614*10616SSebastien.Roy@Sun.COM 
615*10616SSebastien.Roy@Sun.COM dladm_status_t
616*10616SSebastien.Roy@Sun.COM dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay)
617*10616SSebastien.Roy@Sun.COM {
618*10616SSebastien.Roy@Sun.COM 	return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay));
619*10616SSebastien.Roy@Sun.COM }
620*10616SSebastien.Roy@Sun.COM 
621*10616SSebastien.Roy@Sun.COM dladm_status_t
622*10616SSebastien.Roy@Sun.COM dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay)
623*10616SSebastien.Roy@Sun.COM {
624*10616SSebastien.Roy@Sun.COM 	return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay));
625*10616SSebastien.Roy@Sun.COM }
626