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 } 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 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 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 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 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_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 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