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