12b24ab6bSSebastien Roy /* 22b24ab6bSSebastien Roy * CDDL HEADER START 32b24ab6bSSebastien Roy * 42b24ab6bSSebastien Roy * The contents of this file are subject to the terms of the 52b24ab6bSSebastien Roy * Common Development and Distribution License (the "License"). 62b24ab6bSSebastien Roy * You may not use this file except in compliance with the License. 72b24ab6bSSebastien Roy * 82b24ab6bSSebastien Roy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92b24ab6bSSebastien Roy * or http://www.opensolaris.org/os/licensing. 102b24ab6bSSebastien Roy * See the License for the specific language governing permissions 112b24ab6bSSebastien Roy * and limitations under the License. 122b24ab6bSSebastien Roy * 132b24ab6bSSebastien Roy * When distributing Covered Code, include this CDDL HEADER in each 142b24ab6bSSebastien Roy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152b24ab6bSSebastien Roy * If applicable, add the following below this CDDL HEADER, with the 162b24ab6bSSebastien Roy * fields enclosed by brackets "[]" replaced with your own identifying 172b24ab6bSSebastien Roy * information: Portions Copyright [yyyy] [name of copyright owner] 182b24ab6bSSebastien Roy * 192b24ab6bSSebastien Roy * CDDL HEADER END 202b24ab6bSSebastien Roy */ 212b24ab6bSSebastien Roy /* 22*32715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 232b24ab6bSSebastien Roy */ 242b24ab6bSSebastien Roy 252b24ab6bSSebastien Roy #include <assert.h> 262b24ab6bSSebastien Roy #include <stdio.h> 272b24ab6bSSebastien Roy #include <errno.h> 282b24ab6bSSebastien Roy #include <stdlib.h> 292b24ab6bSSebastien Roy #include <unistd.h> 302b24ab6bSSebastien Roy #include <sys/types.h> 312b24ab6bSSebastien Roy #include <fcntl.h> 322b24ab6bSSebastien Roy #include <stropts.h> 332b24ab6bSSebastien Roy #include <string.h> 342b24ab6bSSebastien Roy #include <netdb.h> 352b24ab6bSSebastien Roy #include <sys/conf.h> 362b24ab6bSSebastien Roy #include <sys/socket.h> 372b24ab6bSSebastien Roy #include <netinet/in.h> 382b24ab6bSSebastien Roy #include <inet/iptun.h> 392b24ab6bSSebastien Roy #include <sys/dls.h> 402b24ab6bSSebastien Roy #include <libdlpi.h> 412b24ab6bSSebastien Roy #include <libdladm_impl.h> 422b24ab6bSSebastien Roy #include <libdllink.h> 432b24ab6bSSebastien Roy #include <libdliptun.h> 442b24ab6bSSebastien Roy 452b24ab6bSSebastien Roy /* 462b24ab6bSSebastien Roy * IP Tunneling Administration Library. 472b24ab6bSSebastien Roy * This library is used by dladm(1M) and to configure IP tunnel links. 482b24ab6bSSebastien Roy */ 492b24ab6bSSebastien Roy 502b24ab6bSSebastien Roy #define IPTUN_CONF_TYPE "type" 512b24ab6bSSebastien Roy #define IPTUN_CONF_LADDR "laddr" 522b24ab6bSSebastien Roy #define IPTUN_CONF_RADDR "raddr" 532b24ab6bSSebastien Roy 542b24ab6bSSebastien Roy /* 552b24ab6bSSebastien Roy * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't 562b24ab6bSSebastien Roy * loaded yet, the ioctls may return EAGAIN. We try the ioctl 572b24ab6bSSebastien Roy * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL 582b24ab6bSSebastien Roy * microseconds between attempts. 592b24ab6bSSebastien Roy */ 602b24ab6bSSebastien Roy #define IPTUN_IOCTL_ATTEMPT_LIMIT 3 612b24ab6bSSebastien Roy #define IPTUN_IOCTL_ATTEMPT_INTERVAL 10000 622b24ab6bSSebastien Roy 632b24ab6bSSebastien Roy dladm_status_t 642b24ab6bSSebastien Roy i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp) 652b24ab6bSSebastien Roy { 662b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 672b24ab6bSSebastien Roy uint_t attempt; 682b24ab6bSSebastien Roy 692b24ab6bSSebastien Roy for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) { 702b24ab6bSSebastien Roy if (attempt != 0) 712b24ab6bSSebastien Roy (void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL); 722b24ab6bSSebastien Roy status = (ioctl(dladm_dld_fd(handle), cmd, dp) == 0) ? 732b24ab6bSSebastien Roy DLADM_STATUS_OK : dladm_errno2status(errno); 742b24ab6bSSebastien Roy if (status != DLADM_STATUS_TRYAGAIN) 752b24ab6bSSebastien Roy break; 762b24ab6bSSebastien Roy } 772b24ab6bSSebastien Roy return (status); 782b24ab6bSSebastien Roy } 792b24ab6bSSebastien Roy 802b24ab6bSSebastien Roy /* 812b24ab6bSSebastien Roy * Given tunnel paramaters as supplied by a library consumer, fill in kernel 822b24ab6bSSebastien Roy * parameters to be passed down to the iptun control device. 832b24ab6bSSebastien Roy */ 842b24ab6bSSebastien Roy static dladm_status_t 852b24ab6bSSebastien Roy i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params, 862b24ab6bSSebastien Roy iptun_kparams_t *ik) 872b24ab6bSSebastien Roy { 882b24ab6bSSebastien Roy dladm_status_t status; 892b24ab6bSSebastien Roy struct addrinfo *ai, hints; 902b24ab6bSSebastien Roy iptun_kparams_t tmpik; 912b24ab6bSSebastien Roy iptun_type_t iptuntype = IPTUN_TYPE_UNKNOWN; 922b24ab6bSSebastien Roy 932b24ab6bSSebastien Roy (void) memset(ik, 0, sizeof (*ik)); 942b24ab6bSSebastien Roy 952b24ab6bSSebastien Roy ik->iptun_kparam_linkid = params->iptun_param_linkid; 962b24ab6bSSebastien Roy 972b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_TYPE) { 982b24ab6bSSebastien Roy ik->iptun_kparam_type = iptuntype = params->iptun_param_type; 992b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_TYPE; 1002b24ab6bSSebastien Roy } 1012b24ab6bSSebastien Roy 1022b24ab6bSSebastien Roy if (params->iptun_param_flags & (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) { 1032b24ab6bSSebastien Roy if (iptuntype == IPTUN_TYPE_UNKNOWN) { 1042b24ab6bSSebastien Roy /* 1052b24ab6bSSebastien Roy * We need to get the type of this existing tunnel in 1062b24ab6bSSebastien Roy * order to validate and/or look up the right kind of 1072b24ab6bSSebastien Roy * IP address. 1082b24ab6bSSebastien Roy */ 1092b24ab6bSSebastien Roy tmpik.iptun_kparam_linkid = params->iptun_param_linkid; 1102b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik); 1112b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 1122b24ab6bSSebastien Roy return (status); 1132b24ab6bSSebastien Roy iptuntype = tmpik.iptun_kparam_type; 1142b24ab6bSSebastien Roy } 1152b24ab6bSSebastien Roy 1162b24ab6bSSebastien Roy (void) memset(&hints, 0, sizeof (hints)); 1172b24ab6bSSebastien Roy switch (iptuntype) { 1182b24ab6bSSebastien Roy case IPTUN_TYPE_IPV4: 1192b24ab6bSSebastien Roy case IPTUN_TYPE_6TO4: 1202b24ab6bSSebastien Roy hints.ai_family = AF_INET; 1212b24ab6bSSebastien Roy break; 1222b24ab6bSSebastien Roy case IPTUN_TYPE_IPV6: 1232b24ab6bSSebastien Roy hints.ai_family = AF_INET6; 1242b24ab6bSSebastien Roy break; 1252b24ab6bSSebastien Roy } 1262b24ab6bSSebastien Roy } 1272b24ab6bSSebastien Roy 1282b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 1292b24ab6bSSebastien Roy if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) != 1302b24ab6bSSebastien Roy 0) 1312b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 1322b24ab6bSSebastien Roy if (ai->ai_next != NULL) { 1332b24ab6bSSebastien Roy freeaddrinfo(ai); 1342b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 1352b24ab6bSSebastien Roy } 1362b24ab6bSSebastien Roy (void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr, 1372b24ab6bSSebastien Roy ai->ai_addrlen); 1382b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR; 1392b24ab6bSSebastien Roy freeaddrinfo(ai); 1402b24ab6bSSebastien Roy } 1412b24ab6bSSebastien Roy 1422b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 1432b24ab6bSSebastien Roy if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) != 1442b24ab6bSSebastien Roy 0) 1452b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 1462b24ab6bSSebastien Roy if (ai->ai_next != NULL) { 1472b24ab6bSSebastien Roy freeaddrinfo(ai); 1482b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 1492b24ab6bSSebastien Roy } 1502b24ab6bSSebastien Roy (void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr, 1512b24ab6bSSebastien Roy ai->ai_addrlen); 1522b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR; 1532b24ab6bSSebastien Roy freeaddrinfo(ai); 1542b24ab6bSSebastien Roy } 1552b24ab6bSSebastien Roy 1562b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) { 1572b24ab6bSSebastien Roy ik->iptun_kparam_secinfo = params->iptun_param_secinfo; 1582b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO; 1592b24ab6bSSebastien Roy } 1602b24ab6bSSebastien Roy 1612b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 1622b24ab6bSSebastien Roy } 1632b24ab6bSSebastien Roy 1642b24ab6bSSebastien Roy /* 1652b24ab6bSSebastien Roy * The inverse of i_iptun_kparams(). Given kernel tunnel paramaters as 1662b24ab6bSSebastien Roy * returned from an IPTUN_INFO ioctl, fill in tunnel parameters. 1672b24ab6bSSebastien Roy */ 1682b24ab6bSSebastien Roy static dladm_status_t 1692b24ab6bSSebastien Roy i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params) 1702b24ab6bSSebastien Roy { 1712b24ab6bSSebastien Roy socklen_t salen; 1722b24ab6bSSebastien Roy 1732b24ab6bSSebastien Roy (void) memset(params, 0, sizeof (*params)); 1742b24ab6bSSebastien Roy 1752b24ab6bSSebastien Roy params->iptun_param_linkid = ik->iptun_kparam_linkid; 1762b24ab6bSSebastien Roy 1772b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) { 1782b24ab6bSSebastien Roy params->iptun_param_type = ik->iptun_kparam_type; 1792b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_TYPE; 1802b24ab6bSSebastien Roy } 1812b24ab6bSSebastien Roy 1822b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) { 1832b24ab6bSSebastien Roy salen = ik->iptun_kparam_laddr.ss_family == AF_INET ? 1842b24ab6bSSebastien Roy sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 1852b24ab6bSSebastien Roy if (getnameinfo((const struct sockaddr *) 1862b24ab6bSSebastien Roy &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr, 1872b24ab6bSSebastien Roy sizeof (params->iptun_param_laddr), NULL, 0, 1882b24ab6bSSebastien Roy NI_NUMERICHOST) != 0) { 1892b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 1902b24ab6bSSebastien Roy } 1912b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_LADDR; 1922b24ab6bSSebastien Roy } 1932b24ab6bSSebastien Roy 1942b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) { 1952b24ab6bSSebastien Roy salen = ik->iptun_kparam_raddr.ss_family == AF_INET ? 1962b24ab6bSSebastien Roy sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 1972b24ab6bSSebastien Roy if (getnameinfo((const struct sockaddr *) 1982b24ab6bSSebastien Roy &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr, 1992b24ab6bSSebastien Roy sizeof (params->iptun_param_raddr), NULL, 0, 2002b24ab6bSSebastien Roy NI_NUMERICHOST) != 0) { 2012b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 2022b24ab6bSSebastien Roy } 2032b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_RADDR; 2042b24ab6bSSebastien Roy } 2052b24ab6bSSebastien Roy 2062b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) { 2072b24ab6bSSebastien Roy params->iptun_param_secinfo = ik->iptun_kparam_secinfo; 2082b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_SECINFO; 2092b24ab6bSSebastien Roy } 2102b24ab6bSSebastien Roy 2112b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT) 2122b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT; 2132b24ab6bSSebastien Roy 2142b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL) 2152b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL; 2162b24ab6bSSebastien Roy 2172b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 2182b24ab6bSSebastien Roy } 2192b24ab6bSSebastien Roy 2202b24ab6bSSebastien Roy dladm_status_t 2212b24ab6bSSebastien Roy i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params) 2222b24ab6bSSebastien Roy { 2232b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 2242b24ab6bSSebastien Roy iptun_kparams_t ik; 2252b24ab6bSSebastien Roy 2262b24ab6bSSebastien Roy ik.iptun_kparam_linkid = params->iptun_param_linkid; 2272b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_INFO, &ik); 2282b24ab6bSSebastien Roy if (status == DLADM_STATUS_OK) 2292b24ab6bSSebastien Roy status = i_iptun_params(&ik, params); 2302b24ab6bSSebastien Roy return (status); 2312b24ab6bSSebastien Roy } 2322b24ab6bSSebastien Roy 2332b24ab6bSSebastien Roy /* 2342b24ab6bSSebastien Roy * Read tunnel parameters from persistent storage. Note that the tunnel type 2352b24ab6bSSebastien Roy * is the only thing which must always be in the configuratioh. All other 2362b24ab6bSSebastien Roy * parameters (currently the source and destination addresses) may or may not 2372b24ab6bSSebastien Roy * have been configured, and therefore may not have been set. 2382b24ab6bSSebastien Roy */ 2392b24ab6bSSebastien Roy static dladm_status_t 2402b24ab6bSSebastien Roy i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params) 2412b24ab6bSSebastien Roy { 2422b24ab6bSSebastien Roy dladm_status_t status; 2432b24ab6bSSebastien Roy dladm_conf_t conf; 2442b24ab6bSSebastien Roy datalink_class_t class; 2452b24ab6bSSebastien Roy uint64_t temp; 2462b24ab6bSSebastien Roy 2472b24ab6bSSebastien Roy /* First, make sure that this is an IP tunnel. */ 2482b24ab6bSSebastien Roy if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid, 2492b24ab6bSSebastien Roy NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK) 2502b24ab6bSSebastien Roy return (status); 2512b24ab6bSSebastien Roy if (class != DATALINK_CLASS_IPTUN) 2522b24ab6bSSebastien Roy return (DLADM_STATUS_LINKINVAL); 2532b24ab6bSSebastien Roy 254*32715170SCathy Zhou if ((status = dladm_getsnap_conf(handle, params->iptun_param_linkid, 255*32715170SCathy Zhou &conf)) != DLADM_STATUS_OK) { 2562b24ab6bSSebastien Roy return (status); 257*32715170SCathy Zhou } 2582b24ab6bSSebastien Roy 2592b24ab6bSSebastien Roy params->iptun_param_flags = 0; 2602b24ab6bSSebastien Roy 2612b24ab6bSSebastien Roy if ((status = dladm_get_conf_field(handle, conf, IPTUN_CONF_TYPE, &temp, 2622b24ab6bSSebastien Roy sizeof (temp))) != DLADM_STATUS_OK) 2632b24ab6bSSebastien Roy goto done; 2642b24ab6bSSebastien Roy params->iptun_param_type = (iptun_type_t)temp; 2652b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_TYPE; 2662b24ab6bSSebastien Roy 2672b24ab6bSSebastien Roy if (dladm_get_conf_field(handle, conf, IPTUN_CONF_LADDR, 2682b24ab6bSSebastien Roy params->iptun_param_laddr, sizeof (params->iptun_param_laddr)) == 2692b24ab6bSSebastien Roy DLADM_STATUS_OK) 2702b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_LADDR; 2712b24ab6bSSebastien Roy 2722b24ab6bSSebastien Roy if (dladm_get_conf_field(handle, conf, IPTUN_CONF_RADDR, 2732b24ab6bSSebastien Roy params->iptun_param_raddr, sizeof (params->iptun_param_raddr)) == 2742b24ab6bSSebastien Roy DLADM_STATUS_OK) 2752b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_RADDR; 2762b24ab6bSSebastien Roy 2772b24ab6bSSebastien Roy done: 2782b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 2792b24ab6bSSebastien Roy return (status); 2802b24ab6bSSebastien Roy } 2812b24ab6bSSebastien Roy 2822b24ab6bSSebastien Roy static dladm_status_t 2832b24ab6bSSebastien Roy i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params) 2842b24ab6bSSebastien Roy { 2852b24ab6bSSebastien Roy iptun_kparams_t ik; 2862b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 2872b24ab6bSSebastien Roy 2882b24ab6bSSebastien Roy /* The tunnel type is required for creation. */ 2892b24ab6bSSebastien Roy if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE)) 2902b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPEREQD); 2912b24ab6bSSebastien Roy 2922b24ab6bSSebastien Roy if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK) 2932b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_CREATE, &ik); 2942b24ab6bSSebastien Roy return (status); 2952b24ab6bSSebastien Roy } 2962b24ab6bSSebastien Roy 2972b24ab6bSSebastien Roy static dladm_status_t 2982b24ab6bSSebastien Roy i_iptun_create_db(dladm_handle_t handle, const char *name, 2992b24ab6bSSebastien Roy iptun_params_t *params, uint32_t media) 3002b24ab6bSSebastien Roy { 3012b24ab6bSSebastien Roy dladm_conf_t conf; 3022b24ab6bSSebastien Roy dladm_status_t status; 3032b24ab6bSSebastien Roy uint64_t storage; 3042b24ab6bSSebastien Roy 3052b24ab6bSSebastien Roy status = dladm_create_conf(handle, name, params->iptun_param_linkid, 3062b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, media, &conf); 3072b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3082b24ab6bSSebastien Roy return (status); 3092b24ab6bSSebastien Roy 3102b24ab6bSSebastien Roy assert(params->iptun_param_flags & IPTUN_PARAM_TYPE); 3112b24ab6bSSebastien Roy storage = params->iptun_param_type; 3122b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_TYPE, 3132b24ab6bSSebastien Roy DLADM_TYPE_UINT64, &storage); 3142b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3152b24ab6bSSebastien Roy goto done; 3162b24ab6bSSebastien Roy 3172b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 3182b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR, 3192b24ab6bSSebastien Roy DLADM_TYPE_STR, params->iptun_param_laddr); 3202b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3212b24ab6bSSebastien Roy goto done; 3222b24ab6bSSebastien Roy } 3232b24ab6bSSebastien Roy 3242b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 3252b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR, 3262b24ab6bSSebastien Roy DLADM_TYPE_STR, params->iptun_param_raddr); 3272b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3282b24ab6bSSebastien Roy goto done; 3292b24ab6bSSebastien Roy } 3302b24ab6bSSebastien Roy 3312b24ab6bSSebastien Roy status = dladm_write_conf(handle, conf); 3322b24ab6bSSebastien Roy 3332b24ab6bSSebastien Roy done: 3342b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 3352b24ab6bSSebastien Roy return (status); 3362b24ab6bSSebastien Roy } 3372b24ab6bSSebastien Roy 3382b24ab6bSSebastien Roy static dladm_status_t 3392b24ab6bSSebastien Roy i_iptun_delete_sys(dladm_handle_t handle, datalink_id_t linkid) 3402b24ab6bSSebastien Roy { 3412b24ab6bSSebastien Roy dladm_status_t status; 3422b24ab6bSSebastien Roy 3432b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_DELETE, &linkid); 3442b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3452b24ab6bSSebastien Roy return (status); 3462b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE); 3472b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 3482b24ab6bSSebastien Roy } 3492b24ab6bSSebastien Roy 3502b24ab6bSSebastien Roy static dladm_status_t 3512b24ab6bSSebastien Roy i_iptun_modify_sys(dladm_handle_t handle, const iptun_params_t *params) 3522b24ab6bSSebastien Roy { 3532b24ab6bSSebastien Roy iptun_kparams_t ik; 3542b24ab6bSSebastien Roy dladm_status_t status; 3552b24ab6bSSebastien Roy 3562b24ab6bSSebastien Roy if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK) 3572b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_MODIFY, &ik); 3582b24ab6bSSebastien Roy return (status); 3592b24ab6bSSebastien Roy } 3602b24ab6bSSebastien Roy 3612b24ab6bSSebastien Roy static dladm_status_t 3622b24ab6bSSebastien Roy i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params) 3632b24ab6bSSebastien Roy { 3642b24ab6bSSebastien Roy dladm_conf_t conf; 3652b24ab6bSSebastien Roy dladm_status_t status; 3662b24ab6bSSebastien Roy 3672b24ab6bSSebastien Roy assert(params->iptun_param_flags & 3682b24ab6bSSebastien Roy (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)); 3692b24ab6bSSebastien Roy 3702b24ab6bSSebastien Roy /* 3712b24ab6bSSebastien Roy * The only parameters that can be modified persistently are the local 3722b24ab6bSSebastien Roy * and remote addresses. 3732b24ab6bSSebastien Roy */ 3742b24ab6bSSebastien Roy if (params->iptun_param_flags & ~(IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) 3752b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 3762b24ab6bSSebastien Roy 377*32715170SCathy Zhou status = dladm_open_conf(handle, params->iptun_param_linkid, &conf); 3782b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3792b24ab6bSSebastien Roy return (status); 3802b24ab6bSSebastien Roy 3812b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 3822b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR, 3832b24ab6bSSebastien Roy DLADM_TYPE_STR, (void *)params->iptun_param_laddr); 3842b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3852b24ab6bSSebastien Roy goto done; 3862b24ab6bSSebastien Roy } 3872b24ab6bSSebastien Roy 3882b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 3892b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR, 3902b24ab6bSSebastien Roy DLADM_TYPE_STR, (void *)params->iptun_param_raddr); 3912b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 3922b24ab6bSSebastien Roy goto done; 3932b24ab6bSSebastien Roy } 3942b24ab6bSSebastien Roy 3952b24ab6bSSebastien Roy status = dladm_write_conf(handle, conf); 3962b24ab6bSSebastien Roy 3972b24ab6bSSebastien Roy done: 3982b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 3992b24ab6bSSebastien Roy return (status); 4002b24ab6bSSebastien Roy } 4012b24ab6bSSebastien Roy 4022b24ab6bSSebastien Roy dladm_status_t 4032b24ab6bSSebastien Roy dladm_iptun_create(dladm_handle_t handle, const char *name, 4042b24ab6bSSebastien Roy iptun_params_t *params, uint32_t flags) 4052b24ab6bSSebastien Roy { 4062b24ab6bSSebastien Roy dladm_status_t status; 4072b24ab6bSSebastien Roy uint32_t linkmgmt_flags = flags; 4082b24ab6bSSebastien Roy uint32_t media; 4092b24ab6bSSebastien Roy 4102b24ab6bSSebastien Roy if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE)) 4112b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPEREQD); 4122b24ab6bSSebastien Roy 4132b24ab6bSSebastien Roy switch (params->iptun_param_type) { 4142b24ab6bSSebastien Roy case IPTUN_TYPE_IPV4: 4152b24ab6bSSebastien Roy media = DL_IPV4; 4162b24ab6bSSebastien Roy break; 4172b24ab6bSSebastien Roy case IPTUN_TYPE_IPV6: 4182b24ab6bSSebastien Roy media = DL_IPV6; 4192b24ab6bSSebastien Roy break; 4202b24ab6bSSebastien Roy case IPTUN_TYPE_6TO4: 4212b24ab6bSSebastien Roy media = DL_6TO4; 4222b24ab6bSSebastien Roy break; 4232b24ab6bSSebastien Roy default: 4242b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPE); 4252b24ab6bSSebastien Roy } 4262b24ab6bSSebastien Roy 4272b24ab6bSSebastien Roy status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN, 4282b24ab6bSSebastien Roy media, linkmgmt_flags, ¶ms->iptun_param_linkid); 4292b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 4302b24ab6bSSebastien Roy return (status); 4312b24ab6bSSebastien Roy 4322b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 4332b24ab6bSSebastien Roy status = i_iptun_create_db(handle, name, params, media); 4342b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 4352b24ab6bSSebastien Roy goto done; 4362b24ab6bSSebastien Roy } 4372b24ab6bSSebastien Roy 4382b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 4392b24ab6bSSebastien Roy status = i_iptun_create_sys(handle, params); 4402b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) { 4412b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, 4422b24ab6bSSebastien Roy params->iptun_param_linkid); 4432b24ab6bSSebastien Roy } 4442b24ab6bSSebastien Roy } 4452b24ab6bSSebastien Roy 4462b24ab6bSSebastien Roy done: 4472b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 4482b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, 4492b24ab6bSSebastien Roy params->iptun_param_linkid, flags); 4502b24ab6bSSebastien Roy } 4512b24ab6bSSebastien Roy return (status); 4522b24ab6bSSebastien Roy } 4532b24ab6bSSebastien Roy 4542b24ab6bSSebastien Roy dladm_status_t 4552b24ab6bSSebastien Roy dladm_iptun_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 4562b24ab6bSSebastien Roy { 4572b24ab6bSSebastien Roy dladm_status_t status; 4582b24ab6bSSebastien Roy datalink_class_t class; 4592b24ab6bSSebastien Roy 4602b24ab6bSSebastien Roy /* First, make sure that this is an IP tunnel. */ 4612b24ab6bSSebastien Roy if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 4622b24ab6bSSebastien Roy NULL, 0)) != DLADM_STATUS_OK) 4632b24ab6bSSebastien Roy return (status); 4642b24ab6bSSebastien Roy if (class != DATALINK_CLASS_IPTUN) 4652b24ab6bSSebastien Roy return (DLADM_STATUS_LINKINVAL); 4662b24ab6bSSebastien Roy 4672b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 4682b24ab6bSSebastien Roy /* 4692b24ab6bSSebastien Roy * Note that if i_iptun_delete_sys() fails with 4702b24ab6bSSebastien Roy * DLADM_STATUS_NOTFOUND and the caller also wishes to delete 4712b24ab6bSSebastien Roy * the persistent configuration, we still fall through to the 4722b24ab6bSSebastien Roy * DLADM_OPT_PERSIST case in case the tunnel only exists 4732b24ab6bSSebastien Roy * persistently. 4742b24ab6bSSebastien Roy */ 4752b24ab6bSSebastien Roy status = i_iptun_delete_sys(handle, linkid); 4762b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && 4772b24ab6bSSebastien Roy (status != DLADM_STATUS_NOTFOUND || 4782b24ab6bSSebastien Roy !(flags & DLADM_OPT_PERSIST))) 4792b24ab6bSSebastien Roy return (status); 4802b24ab6bSSebastien Roy } 4812b24ab6bSSebastien Roy 4822b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 4832b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid); 4842b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, 4852b24ab6bSSebastien Roy DLADM_OPT_PERSIST); 4862b24ab6bSSebastien Roy } 4872b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 4882b24ab6bSSebastien Roy } 4892b24ab6bSSebastien Roy 4902b24ab6bSSebastien Roy dladm_status_t 4912b24ab6bSSebastien Roy dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params, 4922b24ab6bSSebastien Roy uint32_t flags) 4932b24ab6bSSebastien Roy { 4942b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 4952b24ab6bSSebastien Roy iptun_params_t old_params; 4962b24ab6bSSebastien Roy 4972b24ab6bSSebastien Roy /* 4982b24ab6bSSebastien Roy * We can only modify the tunnel source, tunnel destination, or IPsec 4992b24ab6bSSebastien Roy * policy. 5002b24ab6bSSebastien Roy */ 5012b24ab6bSSebastien Roy if (!(params->iptun_param_flags & 5022b24ab6bSSebastien Roy (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR|IPTUN_PARAM_SECINFO))) 5032b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 5042b24ab6bSSebastien Roy 5052b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 5062b24ab6bSSebastien Roy /* 5072b24ab6bSSebastien Roy * Before we change the database, save the old configuration 5082b24ab6bSSebastien Roy * so that we can revert back if an error occurs. 5092b24ab6bSSebastien Roy */ 5102b24ab6bSSebastien Roy old_params.iptun_param_linkid = params->iptun_param_linkid; 5112b24ab6bSSebastien Roy status = i_iptun_get_dbparams(handle, &old_params); 5122b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 5132b24ab6bSSebastien Roy return (status); 5142b24ab6bSSebastien Roy /* we'll only need to revert the parameters being modified */ 5152b24ab6bSSebastien Roy old_params.iptun_param_flags = params->iptun_param_flags; 5162b24ab6bSSebastien Roy 5172b24ab6bSSebastien Roy status = i_iptun_modify_db(handle, params); 5182b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 5192b24ab6bSSebastien Roy return (status); 5202b24ab6bSSebastien Roy } 5212b24ab6bSSebastien Roy 5222b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 5232b24ab6bSSebastien Roy status = i_iptun_modify_sys(handle, params); 5242b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) { 5252b24ab6bSSebastien Roy (void) i_iptun_modify_db(handle, &old_params); 5262b24ab6bSSebastien Roy } 5272b24ab6bSSebastien Roy } 5282b24ab6bSSebastien Roy 5292b24ab6bSSebastien Roy return (status); 5302b24ab6bSSebastien Roy } 5312b24ab6bSSebastien Roy 5322b24ab6bSSebastien Roy dladm_status_t 5332b24ab6bSSebastien Roy dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params, 5342b24ab6bSSebastien Roy uint32_t flags) 5352b24ab6bSSebastien Roy { 5362b24ab6bSSebastien Roy if (flags == DLADM_OPT_ACTIVE) 5372b24ab6bSSebastien Roy return (i_iptun_get_sysparams(handle, params)); 5382b24ab6bSSebastien Roy else if (flags == DLADM_OPT_PERSIST) 5392b24ab6bSSebastien Roy return (i_iptun_get_dbparams(handle, params)); 5402b24ab6bSSebastien Roy else 5412b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 5422b24ab6bSSebastien Roy } 5432b24ab6bSSebastien Roy 5442b24ab6bSSebastien Roy static int 5452b24ab6bSSebastien Roy i_iptun_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 5462b24ab6bSSebastien Roy { 5472b24ab6bSSebastien Roy dladm_status_t *statusp = arg; 5482b24ab6bSSebastien Roy dladm_status_t status; 5492b24ab6bSSebastien Roy iptun_params_t params; 5502b24ab6bSSebastien Roy boolean_t id_up = B_FALSE; 5512b24ab6bSSebastien Roy 5522b24ab6bSSebastien Roy status = dladm_up_datalink_id(handle, linkid); 5532b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 5542b24ab6bSSebastien Roy goto done; 5552b24ab6bSSebastien Roy id_up = B_TRUE; 5562b24ab6bSSebastien Roy 5572b24ab6bSSebastien Roy (void) memset(¶ms, 0, sizeof (params)); 5582b24ab6bSSebastien Roy 5592b24ab6bSSebastien Roy params.iptun_param_linkid = linkid; 5602b24ab6bSSebastien Roy if ((status = i_iptun_get_dbparams(handle, ¶ms)) == DLADM_STATUS_OK) 5612b24ab6bSSebastien Roy status = i_iptun_create_sys(handle, ¶ms); 5622b24ab6bSSebastien Roy done: 5632b24ab6bSSebastien Roy if (statusp != NULL) 5642b24ab6bSSebastien Roy *statusp = status; 5652b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && id_up) { 5662b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, 5672b24ab6bSSebastien Roy DLADM_OPT_ACTIVE); 5682b24ab6bSSebastien Roy } 5692b24ab6bSSebastien Roy return (DLADM_WALK_CONTINUE); 5702b24ab6bSSebastien Roy } 5712b24ab6bSSebastien Roy 5722b24ab6bSSebastien Roy static int 5732b24ab6bSSebastien Roy i_iptun_down(dladm_handle_t handle, datalink_id_t linkid, void *arg) 5742b24ab6bSSebastien Roy { 5752b24ab6bSSebastien Roy dladm_status_t *statusp = arg; 5762b24ab6bSSebastien Roy dladm_status_t status; 5772b24ab6bSSebastien Roy 5782b24ab6bSSebastien Roy status = i_iptun_delete_sys(handle, linkid); 5792b24ab6bSSebastien Roy if (statusp != NULL) 5802b24ab6bSSebastien Roy *statusp = status; 5812b24ab6bSSebastien Roy return (DLADM_WALK_CONTINUE); 5822b24ab6bSSebastien Roy } 5832b24ab6bSSebastien Roy 5842b24ab6bSSebastien Roy /* ARGSUSED */ 5852b24ab6bSSebastien Roy dladm_status_t 5862b24ab6bSSebastien Roy dladm_iptun_up(dladm_handle_t handle, datalink_id_t linkid) 5872b24ab6bSSebastien Roy { 5882b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 5892b24ab6bSSebastien Roy 5902b24ab6bSSebastien Roy if (linkid == DATALINK_ALL_LINKID) { 5912b24ab6bSSebastien Roy (void) dladm_walk_datalink_id(i_iptun_up, handle, NULL, 5922b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 5932b24ab6bSSebastien Roy DLADM_OPT_PERSIST); 5942b24ab6bSSebastien Roy } else { 5952b24ab6bSSebastien Roy (void) i_iptun_up(handle, linkid, &status); 5962b24ab6bSSebastien Roy } 5972b24ab6bSSebastien Roy return (status); 5982b24ab6bSSebastien Roy } 5992b24ab6bSSebastien Roy 6002b24ab6bSSebastien Roy dladm_status_t 6012b24ab6bSSebastien Roy dladm_iptun_down(dladm_handle_t handle, datalink_id_t linkid) 6022b24ab6bSSebastien Roy { 6032b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 6042b24ab6bSSebastien Roy 6052b24ab6bSSebastien Roy if (linkid == DATALINK_ALL_LINKID) { 6062b24ab6bSSebastien Roy (void) dladm_walk_datalink_id(i_iptun_down, handle, NULL, 6072b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 6082b24ab6bSSebastien Roy DLADM_OPT_ACTIVE); 6092b24ab6bSSebastien Roy } else { 6102b24ab6bSSebastien Roy (void) i_iptun_down(handle, linkid, &status); 6112b24ab6bSSebastien Roy } 6122b24ab6bSSebastien Roy return (status); 6132b24ab6bSSebastien Roy } 6142b24ab6bSSebastien Roy 6152b24ab6bSSebastien Roy dladm_status_t 6162b24ab6bSSebastien Roy dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay) 6172b24ab6bSSebastien Roy { 6182b24ab6bSSebastien Roy return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay)); 6192b24ab6bSSebastien Roy } 6202b24ab6bSSebastien Roy 6212b24ab6bSSebastien Roy dladm_status_t 6222b24ab6bSSebastien Roy dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay) 6232b24ab6bSSebastien Roy { 6242b24ab6bSSebastien Roy return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay)); 6252b24ab6bSSebastien Roy } 626