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 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 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 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 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 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 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 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 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 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 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 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, ¶ms->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 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 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 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 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(¶ms, 0, sizeof (params)); 560 561 params.iptun_param_linkid = linkid; 562 if ((status = i_iptun_get_dbparams(handle, ¶ms)) == DLADM_STATUS_OK) 563 status = i_iptun_create_sys(handle, ¶ms); 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 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 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 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 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 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