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(8) 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 		case IPTUN_TYPE_UNKNOWN:
126 			return (DLADM_STATUS_BADIPTUNLADDR);
127 		}
128 	}
129 
130 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
131 		if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) !=
132 		    0)
133 			return (DLADM_STATUS_BADIPTUNLADDR);
134 		if (ai->ai_next != NULL) {
135 			freeaddrinfo(ai);
136 			return (DLADM_STATUS_BADIPTUNLADDR);
137 		}
138 		(void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr,
139 		    ai->ai_addrlen);
140 		ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR;
141 		freeaddrinfo(ai);
142 	}
143 
144 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
145 		if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) !=
146 		    0)
147 			return (DLADM_STATUS_BADIPTUNRADDR);
148 		if (ai->ai_next != NULL) {
149 			freeaddrinfo(ai);
150 			return (DLADM_STATUS_BADIPTUNRADDR);
151 		}
152 		(void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr,
153 		    ai->ai_addrlen);
154 		ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR;
155 		freeaddrinfo(ai);
156 	}
157 
158 	if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) {
159 		ik->iptun_kparam_secinfo = params->iptun_param_secinfo;
160 		ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO;
161 	}
162 
163 	return (DLADM_STATUS_OK);
164 }
165 
166 /*
167  * The inverse of i_iptun_kparams().  Given kernel tunnel paramaters as
168  * returned from an IPTUN_INFO ioctl, fill in tunnel parameters.
169  */
170 static dladm_status_t
i_iptun_params(const iptun_kparams_t * ik,iptun_params_t * params)171 i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params)
172 {
173 	socklen_t salen;
174 
175 	(void) memset(params, 0, sizeof (*params));
176 
177 	params->iptun_param_linkid = ik->iptun_kparam_linkid;
178 
179 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) {
180 		params->iptun_param_type = ik->iptun_kparam_type;
181 		params->iptun_param_flags |= IPTUN_PARAM_TYPE;
182 	}
183 
184 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) {
185 		salen = ik->iptun_kparam_laddr.ss_family == AF_INET ?
186 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
187 		if (getnameinfo((const struct sockaddr *)
188 		    &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr,
189 		    sizeof (params->iptun_param_laddr), NULL, 0,
190 		    NI_NUMERICHOST) != 0) {
191 			return (DLADM_STATUS_BADIPTUNLADDR);
192 		}
193 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
194 	}
195 
196 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) {
197 		salen = ik->iptun_kparam_raddr.ss_family == AF_INET ?
198 		    sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
199 		if (getnameinfo((const struct sockaddr *)
200 		    &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr,
201 		    sizeof (params->iptun_param_raddr), NULL, 0,
202 		    NI_NUMERICHOST) != 0) {
203 			return (DLADM_STATUS_BADIPTUNRADDR);
204 		}
205 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
206 	}
207 
208 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) {
209 		params->iptun_param_secinfo = ik->iptun_kparam_secinfo;
210 		params->iptun_param_flags |= IPTUN_PARAM_SECINFO;
211 	}
212 
213 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT)
214 		params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT;
215 
216 	if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL)
217 		params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL;
218 
219 	return (DLADM_STATUS_OK);
220 }
221 
222 dladm_status_t
i_iptun_get_sysparams(dladm_handle_t handle,iptun_params_t * params)223 i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params)
224 {
225 	dladm_status_t	status = DLADM_STATUS_OK;
226 	iptun_kparams_t	ik;
227 
228 	ik.iptun_kparam_linkid = params->iptun_param_linkid;
229 	status = i_iptun_ioctl(handle, IPTUN_INFO, &ik);
230 	if (status == DLADM_STATUS_OK)
231 		status = i_iptun_params(&ik, params);
232 	return (status);
233 }
234 
235 /*
236  * Read tunnel parameters from persistent storage.  Note that the tunnel type
237  * is the only thing which must always be in the configuratioh.  All other
238  * parameters (currently the source and destination addresses) may or may not
239  * have been configured, and therefore may not have been set.
240  */
241 static dladm_status_t
i_iptun_get_dbparams(dladm_handle_t handle,iptun_params_t * params)242 i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params)
243 {
244 	dladm_status_t		status;
245 	dladm_conf_t		conf;
246 	datalink_class_t	class;
247 	uint64_t		temp;
248 
249 	/* First, make sure that this is an IP tunnel. */
250 	if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid,
251 	    NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK)
252 		return (status);
253 	if (class != DATALINK_CLASS_IPTUN)
254 		return (DLADM_STATUS_LINKINVAL);
255 
256 	if ((status = dladm_getsnap_conf(handle, params->iptun_param_linkid,
257 	    &conf)) != DLADM_STATUS_OK) {
258 		return (status);
259 	}
260 
261 	params->iptun_param_flags = 0;
262 
263 	if ((status = dladm_get_conf_field(handle, conf, IPTUN_CONF_TYPE, &temp,
264 	    sizeof (temp))) != DLADM_STATUS_OK)
265 		goto done;
266 	params->iptun_param_type = (iptun_type_t)temp;
267 	params->iptun_param_flags |= IPTUN_PARAM_TYPE;
268 
269 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_LADDR,
270 	    params->iptun_param_laddr, sizeof (params->iptun_param_laddr)) ==
271 	    DLADM_STATUS_OK)
272 		params->iptun_param_flags |= IPTUN_PARAM_LADDR;
273 
274 	if (dladm_get_conf_field(handle, conf, IPTUN_CONF_RADDR,
275 	    params->iptun_param_raddr, sizeof (params->iptun_param_raddr)) ==
276 	    DLADM_STATUS_OK)
277 		params->iptun_param_flags |= IPTUN_PARAM_RADDR;
278 
279 done:
280 	dladm_destroy_conf(handle, conf);
281 	return (status);
282 }
283 
284 static dladm_status_t
i_iptun_create_sys(dladm_handle_t handle,iptun_params_t * params)285 i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params)
286 {
287 	iptun_kparams_t	ik;
288 	dladm_status_t	status = DLADM_STATUS_OK;
289 
290 	/* The tunnel type is required for creation. */
291 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
292 		return (DLADM_STATUS_IPTUNTYPEREQD);
293 
294 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
295 		status = i_iptun_ioctl(handle, IPTUN_CREATE, &ik);
296 	return (status);
297 }
298 
299 static dladm_status_t
i_iptun_create_db(dladm_handle_t handle,const char * name,iptun_params_t * params,uint32_t media)300 i_iptun_create_db(dladm_handle_t handle, const char *name,
301     iptun_params_t *params, uint32_t media)
302 {
303 	dladm_conf_t	conf;
304 	dladm_status_t	status;
305 	uint64_t	storage;
306 
307 	status = dladm_create_conf(handle, name, params->iptun_param_linkid,
308 	    DATALINK_CLASS_IPTUN, media, &conf);
309 	if (status != DLADM_STATUS_OK)
310 		return (status);
311 
312 	assert(params->iptun_param_flags & IPTUN_PARAM_TYPE);
313 	storage = params->iptun_param_type;
314 	status = dladm_set_conf_field(handle, conf, IPTUN_CONF_TYPE,
315 	    DLADM_TYPE_UINT64, &storage);
316 	if (status != DLADM_STATUS_OK)
317 		goto done;
318 
319 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
320 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
321 		    DLADM_TYPE_STR, params->iptun_param_laddr);
322 		if (status != DLADM_STATUS_OK)
323 			goto done;
324 	}
325 
326 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
327 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
328 		    DLADM_TYPE_STR, params->iptun_param_raddr);
329 		if (status != DLADM_STATUS_OK)
330 			goto done;
331 	}
332 
333 	status = dladm_write_conf(handle, conf);
334 
335 done:
336 	dladm_destroy_conf(handle, conf);
337 	return (status);
338 }
339 
340 static dladm_status_t
i_iptun_delete_sys(dladm_handle_t handle,datalink_id_t linkid)341 i_iptun_delete_sys(dladm_handle_t handle, datalink_id_t linkid)
342 {
343 	dladm_status_t status;
344 
345 	status = i_iptun_ioctl(handle, IPTUN_DELETE, &linkid);
346 	if (status != DLADM_STATUS_OK)
347 		return (status);
348 	(void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE);
349 	return (DLADM_STATUS_OK);
350 }
351 
352 static dladm_status_t
i_iptun_modify_sys(dladm_handle_t handle,const iptun_params_t * params)353 i_iptun_modify_sys(dladm_handle_t handle, const iptun_params_t *params)
354 {
355 	iptun_kparams_t	ik;
356 	dladm_status_t	status;
357 
358 	if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK)
359 		status = i_iptun_ioctl(handle, IPTUN_MODIFY, &ik);
360 	return (status);
361 }
362 
363 static dladm_status_t
i_iptun_modify_db(dladm_handle_t handle,const iptun_params_t * params)364 i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params)
365 {
366 	dladm_conf_t	conf;
367 	dladm_status_t	status;
368 
369 	assert(params->iptun_param_flags &
370 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR));
371 
372 	/*
373 	 * The only parameters that can be modified persistently are the local
374 	 * and remote addresses.
375 	 */
376 	if (params->iptun_param_flags & ~(IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR))
377 		return (DLADM_STATUS_BADARG);
378 
379 	status = dladm_open_conf(handle, params->iptun_param_linkid, &conf);
380 	if (status != DLADM_STATUS_OK)
381 		return (status);
382 
383 	if (params->iptun_param_flags & IPTUN_PARAM_LADDR) {
384 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR,
385 		    DLADM_TYPE_STR, (void *)params->iptun_param_laddr);
386 		if (status != DLADM_STATUS_OK)
387 			goto done;
388 	}
389 
390 	if (params->iptun_param_flags & IPTUN_PARAM_RADDR) {
391 		status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR,
392 		    DLADM_TYPE_STR, (void *)params->iptun_param_raddr);
393 		if (status != DLADM_STATUS_OK)
394 			goto done;
395 	}
396 
397 	status = dladm_write_conf(handle, conf);
398 
399 done:
400 	dladm_destroy_conf(handle, conf);
401 	return (status);
402 }
403 
404 dladm_status_t
dladm_iptun_create(dladm_handle_t handle,const char * name,iptun_params_t * params,uint32_t flags)405 dladm_iptun_create(dladm_handle_t handle, const char *name,
406     iptun_params_t *params, uint32_t flags)
407 {
408 	dladm_status_t	status;
409 	uint32_t	linkmgmt_flags = flags;
410 	uint32_t	media;
411 
412 	if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE))
413 		return (DLADM_STATUS_IPTUNTYPEREQD);
414 
415 	switch (params->iptun_param_type) {
416 	case IPTUN_TYPE_IPV4:
417 		media = DL_IPV4;
418 		break;
419 	case IPTUN_TYPE_IPV6:
420 		media = DL_IPV6;
421 		break;
422 	case IPTUN_TYPE_6TO4:
423 		media = DL_6TO4;
424 		break;
425 	default:
426 		return (DLADM_STATUS_IPTUNTYPE);
427 	}
428 
429 	status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN,
430 	    media, linkmgmt_flags, &params->iptun_param_linkid);
431 	if (status != DLADM_STATUS_OK)
432 		return (status);
433 
434 	if (flags & DLADM_OPT_PERSIST) {
435 		status = i_iptun_create_db(handle, name, params, media);
436 		if (status != DLADM_STATUS_OK)
437 			goto done;
438 	}
439 
440 	if (flags & DLADM_OPT_ACTIVE) {
441 		status = i_iptun_create_sys(handle, params);
442 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
443 			(void) dladm_remove_conf(handle,
444 			    params->iptun_param_linkid);
445 		}
446 	}
447 
448 done:
449 	if (status != DLADM_STATUS_OK) {
450 		(void) dladm_destroy_datalink_id(handle,
451 		    params->iptun_param_linkid, flags);
452 	}
453 	return (status);
454 }
455 
456 dladm_status_t
dladm_iptun_delete(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)457 dladm_iptun_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
458 {
459 	dladm_status_t		status;
460 	datalink_class_t	class;
461 
462 	/* First, make sure that this is an IP tunnel. */
463 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
464 	    NULL, 0)) != DLADM_STATUS_OK)
465 		return (status);
466 	if (class != DATALINK_CLASS_IPTUN)
467 		return (DLADM_STATUS_LINKINVAL);
468 
469 	if (flags & DLADM_OPT_ACTIVE) {
470 		/*
471 		 * Note that if i_iptun_delete_sys() fails with
472 		 * DLADM_STATUS_NOTFOUND and the caller also wishes to delete
473 		 * the persistent configuration, we still fall through to the
474 		 * DLADM_OPT_PERSIST case in case the tunnel only exists
475 		 * persistently.
476 		 */
477 		status = i_iptun_delete_sys(handle, linkid);
478 		if (status != DLADM_STATUS_OK &&
479 		    (status != DLADM_STATUS_NOTFOUND ||
480 		    !(flags & DLADM_OPT_PERSIST)))
481 			return (status);
482 	}
483 
484 	if (flags & DLADM_OPT_PERSIST) {
485 		(void) dladm_remove_conf(handle, linkid);
486 		(void) dladm_destroy_datalink_id(handle, linkid,
487 		    DLADM_OPT_PERSIST);
488 	}
489 	return (DLADM_STATUS_OK);
490 }
491 
492 dladm_status_t
dladm_iptun_modify(dladm_handle_t handle,const iptun_params_t * params,uint32_t flags)493 dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params,
494     uint32_t flags)
495 {
496 	dladm_status_t	status = DLADM_STATUS_OK;
497 	iptun_params_t	old_params;
498 
499 	/*
500 	 * We can only modify the tunnel source, tunnel destination, or IPsec
501 	 * policy.
502 	 */
503 	if (!(params->iptun_param_flags &
504 	    (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR|IPTUN_PARAM_SECINFO)))
505 		return (DLADM_STATUS_BADARG);
506 
507 	if (flags & DLADM_OPT_PERSIST) {
508 		/*
509 		 * Before we change the database, save the old configuration
510 		 * so that we can revert back if an error occurs.
511 		 */
512 		old_params.iptun_param_linkid = params->iptun_param_linkid;
513 		status = i_iptun_get_dbparams(handle, &old_params);
514 		if (status != DLADM_STATUS_OK)
515 			return (status);
516 		/* we'll only need to revert the parameters being modified */
517 		old_params.iptun_param_flags = params->iptun_param_flags;
518 
519 		status = i_iptun_modify_db(handle, params);
520 		if (status != DLADM_STATUS_OK)
521 			return (status);
522 	}
523 
524 	if (flags & DLADM_OPT_ACTIVE) {
525 		status = i_iptun_modify_sys(handle, params);
526 		if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) {
527 			(void) i_iptun_modify_db(handle, &old_params);
528 		}
529 	}
530 
531 	return (status);
532 }
533 
534 dladm_status_t
dladm_iptun_getparams(dladm_handle_t handle,iptun_params_t * params,uint32_t flags)535 dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params,
536     uint32_t flags)
537 {
538 	if (flags == DLADM_OPT_ACTIVE)
539 		return (i_iptun_get_sysparams(handle, params));
540 	else if (flags == DLADM_OPT_PERSIST)
541 		return (i_iptun_get_dbparams(handle, params));
542 	else
543 		return (DLADM_STATUS_BADARG);
544 }
545 
546 static int
i_iptun_up(dladm_handle_t handle,datalink_id_t linkid,void * arg)547 i_iptun_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
548 {
549 	dladm_status_t	*statusp = arg;
550 	dladm_status_t	status;
551 	iptun_params_t	params;
552 	boolean_t	id_up = B_FALSE;
553 
554 	status = dladm_up_datalink_id(handle, linkid);
555 	if (status != DLADM_STATUS_OK)
556 		goto done;
557 	id_up = B_TRUE;
558 
559 	(void) memset(&params, 0, sizeof (params));
560 
561 	params.iptun_param_linkid = linkid;
562 	if ((status = i_iptun_get_dbparams(handle, &params)) == DLADM_STATUS_OK)
563 		status = i_iptun_create_sys(handle, &params);
564 done:
565 	if (statusp != NULL)
566 		*statusp = status;
567 	if (status != DLADM_STATUS_OK && id_up) {
568 		(void) dladm_destroy_datalink_id(handle, linkid,
569 		    DLADM_OPT_ACTIVE);
570 	}
571 	return (DLADM_WALK_CONTINUE);
572 }
573 
574 static int
i_iptun_down(dladm_handle_t handle,datalink_id_t linkid,void * arg)575 i_iptun_down(dladm_handle_t handle, datalink_id_t linkid, void *arg)
576 {
577 	dladm_status_t	*statusp = arg;
578 	dladm_status_t	status;
579 
580 	status = i_iptun_delete_sys(handle, linkid);
581 	if (statusp != NULL)
582 		*statusp = status;
583 	return (DLADM_WALK_CONTINUE);
584 }
585 
586 /* ARGSUSED */
587 dladm_status_t
dladm_iptun_up(dladm_handle_t handle,datalink_id_t linkid)588 dladm_iptun_up(dladm_handle_t handle, datalink_id_t linkid)
589 {
590 	dladm_status_t status = DLADM_STATUS_OK;
591 
592 	if (linkid == DATALINK_ALL_LINKID) {
593 		(void) dladm_walk_datalink_id(i_iptun_up, handle, NULL,
594 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
595 		    DLADM_OPT_PERSIST);
596 	} else {
597 		(void) i_iptun_up(handle, linkid, &status);
598 	}
599 	return (status);
600 }
601 
602 dladm_status_t
dladm_iptun_down(dladm_handle_t handle,datalink_id_t linkid)603 dladm_iptun_down(dladm_handle_t handle, datalink_id_t linkid)
604 {
605 	dladm_status_t status = DLADM_STATUS_OK;
606 
607 	if (linkid == DATALINK_ALL_LINKID) {
608 		(void) dladm_walk_datalink_id(i_iptun_down, handle, NULL,
609 		    DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
610 		    DLADM_OPT_ACTIVE);
611 	} else {
612 		(void) i_iptun_down(handle, linkid, &status);
613 	}
614 	return (status);
615 }
616 
617 dladm_status_t
dladm_iptun_set6to4relay(dladm_handle_t handle,struct in_addr * relay)618 dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay)
619 {
620 	return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay));
621 }
622 
623 dladm_status_t
dladm_iptun_get6to4relay(dladm_handle_t handle,struct in_addr * relay)624 dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay)
625 {
626 	return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay));
627 }
628