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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <assert.h> 27 #include <stdio.h> 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <sys/types.h> 32 #include <fcntl.h> 33 #include <stropts.h> 34 #include <string.h> 35 #include <netdb.h> 36 #include <sys/conf.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 #include <inet/iptun.h> 40 #include <sys/dls.h> 41 #include <libdlpi.h> 42 #include <libdladm_impl.h> 43 #include <libdllink.h> 44 #include <libdliptun.h> 45 46 /* 47 * IP Tunneling Administration Library. 48 * This library is used by dladm(1M) and to configure IP tunnel links. 49 */ 50 51 #define IPTUN_CONF_TYPE "type" 52 #define IPTUN_CONF_LADDR "laddr" 53 #define IPTUN_CONF_RADDR "raddr" 54 55 /* 56 * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't 57 * loaded yet, the ioctls may return EAGAIN. We try the ioctl 58 * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL 59 * microseconds between attempts. 60 */ 61 #define IPTUN_IOCTL_ATTEMPT_LIMIT 3 62 #define IPTUN_IOCTL_ATTEMPT_INTERVAL 10000 63 64 dladm_status_t 65 i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp) 66 { 67 dladm_status_t status = DLADM_STATUS_OK; 68 uint_t attempt; 69 70 for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) { 71 if (attempt != 0) 72 (void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL); 73 status = (ioctl(dladm_dld_fd(handle), cmd, dp) == 0) ? 74 DLADM_STATUS_OK : dladm_errno2status(errno); 75 if (status != DLADM_STATUS_TRYAGAIN) 76 break; 77 } 78 return (status); 79 } 80 81 /* 82 * Given tunnel paramaters as supplied by a library consumer, fill in kernel 83 * parameters to be passed down to the iptun control device. 84 */ 85 static dladm_status_t 86 i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params, 87 iptun_kparams_t *ik) 88 { 89 dladm_status_t status; 90 struct addrinfo *ai, hints; 91 iptun_kparams_t tmpik; 92 iptun_type_t iptuntype = IPTUN_TYPE_UNKNOWN; 93 94 (void) memset(ik, 0, sizeof (*ik)); 95 96 ik->iptun_kparam_linkid = params->iptun_param_linkid; 97 98 if (params->iptun_param_flags & IPTUN_PARAM_TYPE) { 99 ik->iptun_kparam_type = iptuntype = params->iptun_param_type; 100 ik->iptun_kparam_flags |= IPTUN_KPARAM_TYPE; 101 } 102 103 if (params->iptun_param_flags & (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) { 104 if (iptuntype == IPTUN_TYPE_UNKNOWN) { 105 /* 106 * We need to get the type of this existing tunnel in 107 * order to validate and/or look up the right kind of 108 * IP address. 109 */ 110 tmpik.iptun_kparam_linkid = params->iptun_param_linkid; 111 status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik); 112 if (status != DLADM_STATUS_OK) 113 return (status); 114 iptuntype = tmpik.iptun_kparam_type; 115 } 116 117 (void) memset(&hints, 0, sizeof (hints)); 118 switch (iptuntype) { 119 case IPTUN_TYPE_IPV4: 120 case IPTUN_TYPE_6TO4: 121 hints.ai_family = AF_INET; 122 break; 123 case IPTUN_TYPE_IPV6: 124 hints.ai_family = AF_INET6; 125 break; 126 } 127 } 128 129 if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 130 if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) != 131 0) 132 return (DLADM_STATUS_BADIPTUNLADDR); 133 if (ai->ai_next != NULL) { 134 freeaddrinfo(ai); 135 return (DLADM_STATUS_BADIPTUNLADDR); 136 } 137 (void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr, 138 ai->ai_addrlen); 139 ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR; 140 freeaddrinfo(ai); 141 } 142 143 if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 144 if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) != 145 0) 146 return (DLADM_STATUS_BADIPTUNRADDR); 147 if (ai->ai_next != NULL) { 148 freeaddrinfo(ai); 149 return (DLADM_STATUS_BADIPTUNRADDR); 150 } 151 (void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr, 152 ai->ai_addrlen); 153 ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR; 154 freeaddrinfo(ai); 155 } 156 157 if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) { 158 ik->iptun_kparam_secinfo = params->iptun_param_secinfo; 159 ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO; 160 } 161 162 return (DLADM_STATUS_OK); 163 } 164 165 /* 166 * The inverse of i_iptun_kparams(). Given kernel tunnel paramaters as 167 * returned from an IPTUN_INFO ioctl, fill in tunnel parameters. 168 */ 169 static dladm_status_t 170 i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params) 171 { 172 socklen_t salen; 173 174 (void) memset(params, 0, sizeof (*params)); 175 176 params->iptun_param_linkid = ik->iptun_kparam_linkid; 177 178 if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) { 179 params->iptun_param_type = ik->iptun_kparam_type; 180 params->iptun_param_flags |= IPTUN_PARAM_TYPE; 181 } 182 183 if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) { 184 salen = ik->iptun_kparam_laddr.ss_family == AF_INET ? 185 sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 186 if (getnameinfo((const struct sockaddr *) 187 &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr, 188 sizeof (params->iptun_param_laddr), NULL, 0, 189 NI_NUMERICHOST) != 0) { 190 return (DLADM_STATUS_BADIPTUNLADDR); 191 } 192 params->iptun_param_flags |= IPTUN_PARAM_LADDR; 193 } 194 195 if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) { 196 salen = ik->iptun_kparam_raddr.ss_family == AF_INET ? 197 sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 198 if (getnameinfo((const struct sockaddr *) 199 &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr, 200 sizeof (params->iptun_param_raddr), NULL, 0, 201 NI_NUMERICHOST) != 0) { 202 return (DLADM_STATUS_BADIPTUNRADDR); 203 } 204 params->iptun_param_flags |= IPTUN_PARAM_RADDR; 205 } 206 207 if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) { 208 params->iptun_param_secinfo = ik->iptun_kparam_secinfo; 209 params->iptun_param_flags |= IPTUN_PARAM_SECINFO; 210 } 211 212 if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT) 213 params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT; 214 215 if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL) 216 params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL; 217 218 return (DLADM_STATUS_OK); 219 } 220 221 dladm_status_t 222 i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params) 223 { 224 dladm_status_t status = DLADM_STATUS_OK; 225 iptun_kparams_t ik; 226 227 ik.iptun_kparam_linkid = params->iptun_param_linkid; 228 status = i_iptun_ioctl(handle, IPTUN_INFO, &ik); 229 if (status == DLADM_STATUS_OK) 230 status = i_iptun_params(&ik, params); 231 return (status); 232 } 233 234 /* 235 * Read tunnel parameters from persistent storage. Note that the tunnel type 236 * is the only thing which must always be in the configuratioh. All other 237 * parameters (currently the source and destination addresses) may or may not 238 * have been configured, and therefore may not have been set. 239 */ 240 static dladm_status_t 241 i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params) 242 { 243 dladm_status_t status; 244 dladm_conf_t conf; 245 datalink_class_t class; 246 uint64_t temp; 247 248 /* First, make sure that this is an IP tunnel. */ 249 if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid, 250 NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK) 251 return (status); 252 if (class != DATALINK_CLASS_IPTUN) 253 return (DLADM_STATUS_LINKINVAL); 254 255 status = dladm_read_conf(handle, params->iptun_param_linkid, &conf); 256 if (status != DLADM_STATUS_OK) 257 return (status); 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 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 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 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 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 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_read_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 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, ¶ms->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 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 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 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 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(¶ms, 0, sizeof (params)); 558 559 params.iptun_param_linkid = linkid; 560 if ((status = i_iptun_get_dbparams(handle, ¶ms)) == DLADM_STATUS_OK) 561 status = i_iptun_create_sys(handle, ¶ms); 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 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 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 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 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 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