1*2b24ab6bSSebastien Roy /* 2*2b24ab6bSSebastien Roy * CDDL HEADER START 3*2b24ab6bSSebastien Roy * 4*2b24ab6bSSebastien Roy * The contents of this file are subject to the terms of the 5*2b24ab6bSSebastien Roy * Common Development and Distribution License (the "License"). 6*2b24ab6bSSebastien Roy * You may not use this file except in compliance with the License. 7*2b24ab6bSSebastien Roy * 8*2b24ab6bSSebastien Roy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2b24ab6bSSebastien Roy * or http://www.opensolaris.org/os/licensing. 10*2b24ab6bSSebastien Roy * See the License for the specific language governing permissions 11*2b24ab6bSSebastien Roy * and limitations under the License. 12*2b24ab6bSSebastien Roy * 13*2b24ab6bSSebastien Roy * When distributing Covered Code, include this CDDL HEADER in each 14*2b24ab6bSSebastien Roy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2b24ab6bSSebastien Roy * If applicable, add the following below this CDDL HEADER, with the 16*2b24ab6bSSebastien Roy * fields enclosed by brackets "[]" replaced with your own identifying 17*2b24ab6bSSebastien Roy * information: Portions Copyright [yyyy] [name of copyright owner] 18*2b24ab6bSSebastien Roy * 19*2b24ab6bSSebastien Roy * CDDL HEADER END 20*2b24ab6bSSebastien Roy */ 21*2b24ab6bSSebastien Roy /* 22*2b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*2b24ab6bSSebastien Roy * Use is subject to license terms. 24*2b24ab6bSSebastien Roy */ 25*2b24ab6bSSebastien Roy 26*2b24ab6bSSebastien Roy #include <assert.h> 27*2b24ab6bSSebastien Roy #include <stdio.h> 28*2b24ab6bSSebastien Roy #include <errno.h> 29*2b24ab6bSSebastien Roy #include <stdlib.h> 30*2b24ab6bSSebastien Roy #include <unistd.h> 31*2b24ab6bSSebastien Roy #include <sys/types.h> 32*2b24ab6bSSebastien Roy #include <fcntl.h> 33*2b24ab6bSSebastien Roy #include <stropts.h> 34*2b24ab6bSSebastien Roy #include <string.h> 35*2b24ab6bSSebastien Roy #include <netdb.h> 36*2b24ab6bSSebastien Roy #include <sys/conf.h> 37*2b24ab6bSSebastien Roy #include <sys/socket.h> 38*2b24ab6bSSebastien Roy #include <netinet/in.h> 39*2b24ab6bSSebastien Roy #include <inet/iptun.h> 40*2b24ab6bSSebastien Roy #include <sys/dls.h> 41*2b24ab6bSSebastien Roy #include <libdlpi.h> 42*2b24ab6bSSebastien Roy #include <libdladm_impl.h> 43*2b24ab6bSSebastien Roy #include <libdllink.h> 44*2b24ab6bSSebastien Roy #include <libdliptun.h> 45*2b24ab6bSSebastien Roy 46*2b24ab6bSSebastien Roy /* 47*2b24ab6bSSebastien Roy * IP Tunneling Administration Library. 48*2b24ab6bSSebastien Roy * This library is used by dladm(1M) and to configure IP tunnel links. 49*2b24ab6bSSebastien Roy */ 50*2b24ab6bSSebastien Roy 51*2b24ab6bSSebastien Roy #define IPTUN_CONF_TYPE "type" 52*2b24ab6bSSebastien Roy #define IPTUN_CONF_LADDR "laddr" 53*2b24ab6bSSebastien Roy #define IPTUN_CONF_RADDR "raddr" 54*2b24ab6bSSebastien Roy 55*2b24ab6bSSebastien Roy /* 56*2b24ab6bSSebastien Roy * If IPTUN_CREATE and IPTUN_MODIFY include IPsec policy and IPsec hasn't 57*2b24ab6bSSebastien Roy * loaded yet, the ioctls may return EAGAIN. We try the ioctl 58*2b24ab6bSSebastien Roy * IPTUN_IOCTL_ATTEMPT_LIMIT times and wait IPTUN_IOCTL_ATTEMPT_INTERVAL 59*2b24ab6bSSebastien Roy * microseconds between attempts. 60*2b24ab6bSSebastien Roy */ 61*2b24ab6bSSebastien Roy #define IPTUN_IOCTL_ATTEMPT_LIMIT 3 62*2b24ab6bSSebastien Roy #define IPTUN_IOCTL_ATTEMPT_INTERVAL 10000 63*2b24ab6bSSebastien Roy 64*2b24ab6bSSebastien Roy dladm_status_t 65*2b24ab6bSSebastien Roy i_iptun_ioctl(dladm_handle_t handle, int cmd, void *dp) 66*2b24ab6bSSebastien Roy { 67*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 68*2b24ab6bSSebastien Roy uint_t attempt; 69*2b24ab6bSSebastien Roy 70*2b24ab6bSSebastien Roy for (attempt = 0; attempt < IPTUN_IOCTL_ATTEMPT_LIMIT; attempt++) { 71*2b24ab6bSSebastien Roy if (attempt != 0) 72*2b24ab6bSSebastien Roy (void) usleep(IPTUN_IOCTL_ATTEMPT_INTERVAL); 73*2b24ab6bSSebastien Roy status = (ioctl(dladm_dld_fd(handle), cmd, dp) == 0) ? 74*2b24ab6bSSebastien Roy DLADM_STATUS_OK : dladm_errno2status(errno); 75*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_TRYAGAIN) 76*2b24ab6bSSebastien Roy break; 77*2b24ab6bSSebastien Roy } 78*2b24ab6bSSebastien Roy return (status); 79*2b24ab6bSSebastien Roy } 80*2b24ab6bSSebastien Roy 81*2b24ab6bSSebastien Roy /* 82*2b24ab6bSSebastien Roy * Given tunnel paramaters as supplied by a library consumer, fill in kernel 83*2b24ab6bSSebastien Roy * parameters to be passed down to the iptun control device. 84*2b24ab6bSSebastien Roy */ 85*2b24ab6bSSebastien Roy static dladm_status_t 86*2b24ab6bSSebastien Roy i_iptun_kparams(dladm_handle_t handle, const iptun_params_t *params, 87*2b24ab6bSSebastien Roy iptun_kparams_t *ik) 88*2b24ab6bSSebastien Roy { 89*2b24ab6bSSebastien Roy dladm_status_t status; 90*2b24ab6bSSebastien Roy struct addrinfo *ai, hints; 91*2b24ab6bSSebastien Roy iptun_kparams_t tmpik; 92*2b24ab6bSSebastien Roy iptun_type_t iptuntype = IPTUN_TYPE_UNKNOWN; 93*2b24ab6bSSebastien Roy 94*2b24ab6bSSebastien Roy (void) memset(ik, 0, sizeof (*ik)); 95*2b24ab6bSSebastien Roy 96*2b24ab6bSSebastien Roy ik->iptun_kparam_linkid = params->iptun_param_linkid; 97*2b24ab6bSSebastien Roy 98*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_TYPE) { 99*2b24ab6bSSebastien Roy ik->iptun_kparam_type = iptuntype = params->iptun_param_type; 100*2b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_TYPE; 101*2b24ab6bSSebastien Roy } 102*2b24ab6bSSebastien Roy 103*2b24ab6bSSebastien Roy if (params->iptun_param_flags & (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) { 104*2b24ab6bSSebastien Roy if (iptuntype == IPTUN_TYPE_UNKNOWN) { 105*2b24ab6bSSebastien Roy /* 106*2b24ab6bSSebastien Roy * We need to get the type of this existing tunnel in 107*2b24ab6bSSebastien Roy * order to validate and/or look up the right kind of 108*2b24ab6bSSebastien Roy * IP address. 109*2b24ab6bSSebastien Roy */ 110*2b24ab6bSSebastien Roy tmpik.iptun_kparam_linkid = params->iptun_param_linkid; 111*2b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_INFO, &tmpik); 112*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 113*2b24ab6bSSebastien Roy return (status); 114*2b24ab6bSSebastien Roy iptuntype = tmpik.iptun_kparam_type; 115*2b24ab6bSSebastien Roy } 116*2b24ab6bSSebastien Roy 117*2b24ab6bSSebastien Roy (void) memset(&hints, 0, sizeof (hints)); 118*2b24ab6bSSebastien Roy switch (iptuntype) { 119*2b24ab6bSSebastien Roy case IPTUN_TYPE_IPV4: 120*2b24ab6bSSebastien Roy case IPTUN_TYPE_6TO4: 121*2b24ab6bSSebastien Roy hints.ai_family = AF_INET; 122*2b24ab6bSSebastien Roy break; 123*2b24ab6bSSebastien Roy case IPTUN_TYPE_IPV6: 124*2b24ab6bSSebastien Roy hints.ai_family = AF_INET6; 125*2b24ab6bSSebastien Roy break; 126*2b24ab6bSSebastien Roy } 127*2b24ab6bSSebastien Roy } 128*2b24ab6bSSebastien Roy 129*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 130*2b24ab6bSSebastien Roy if (getaddrinfo(params->iptun_param_laddr, NULL, &hints, &ai) != 131*2b24ab6bSSebastien Roy 0) 132*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 133*2b24ab6bSSebastien Roy if (ai->ai_next != NULL) { 134*2b24ab6bSSebastien Roy freeaddrinfo(ai); 135*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 136*2b24ab6bSSebastien Roy } 137*2b24ab6bSSebastien Roy (void) memcpy(&ik->iptun_kparam_laddr, ai->ai_addr, 138*2b24ab6bSSebastien Roy ai->ai_addrlen); 139*2b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_LADDR; 140*2b24ab6bSSebastien Roy freeaddrinfo(ai); 141*2b24ab6bSSebastien Roy } 142*2b24ab6bSSebastien Roy 143*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 144*2b24ab6bSSebastien Roy if (getaddrinfo(params->iptun_param_raddr, NULL, &hints, &ai) != 145*2b24ab6bSSebastien Roy 0) 146*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 147*2b24ab6bSSebastien Roy if (ai->ai_next != NULL) { 148*2b24ab6bSSebastien Roy freeaddrinfo(ai); 149*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 150*2b24ab6bSSebastien Roy } 151*2b24ab6bSSebastien Roy (void) memcpy(&ik->iptun_kparam_raddr, ai->ai_addr, 152*2b24ab6bSSebastien Roy ai->ai_addrlen); 153*2b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_RADDR; 154*2b24ab6bSSebastien Roy freeaddrinfo(ai); 155*2b24ab6bSSebastien Roy } 156*2b24ab6bSSebastien Roy 157*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_SECINFO) { 158*2b24ab6bSSebastien Roy ik->iptun_kparam_secinfo = params->iptun_param_secinfo; 159*2b24ab6bSSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO; 160*2b24ab6bSSebastien Roy } 161*2b24ab6bSSebastien Roy 162*2b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 163*2b24ab6bSSebastien Roy } 164*2b24ab6bSSebastien Roy 165*2b24ab6bSSebastien Roy /* 166*2b24ab6bSSebastien Roy * The inverse of i_iptun_kparams(). Given kernel tunnel paramaters as 167*2b24ab6bSSebastien Roy * returned from an IPTUN_INFO ioctl, fill in tunnel parameters. 168*2b24ab6bSSebastien Roy */ 169*2b24ab6bSSebastien Roy static dladm_status_t 170*2b24ab6bSSebastien Roy i_iptun_params(const iptun_kparams_t *ik, iptun_params_t *params) 171*2b24ab6bSSebastien Roy { 172*2b24ab6bSSebastien Roy socklen_t salen; 173*2b24ab6bSSebastien Roy 174*2b24ab6bSSebastien Roy (void) memset(params, 0, sizeof (*params)); 175*2b24ab6bSSebastien Roy 176*2b24ab6bSSebastien Roy params->iptun_param_linkid = ik->iptun_kparam_linkid; 177*2b24ab6bSSebastien Roy 178*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) { 179*2b24ab6bSSebastien Roy params->iptun_param_type = ik->iptun_kparam_type; 180*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_TYPE; 181*2b24ab6bSSebastien Roy } 182*2b24ab6bSSebastien Roy 183*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) { 184*2b24ab6bSSebastien Roy salen = ik->iptun_kparam_laddr.ss_family == AF_INET ? 185*2b24ab6bSSebastien Roy sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 186*2b24ab6bSSebastien Roy if (getnameinfo((const struct sockaddr *) 187*2b24ab6bSSebastien Roy &ik->iptun_kparam_laddr, salen, params->iptun_param_laddr, 188*2b24ab6bSSebastien Roy sizeof (params->iptun_param_laddr), NULL, 0, 189*2b24ab6bSSebastien Roy NI_NUMERICHOST) != 0) { 190*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNLADDR); 191*2b24ab6bSSebastien Roy } 192*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_LADDR; 193*2b24ab6bSSebastien Roy } 194*2b24ab6bSSebastien Roy 195*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) { 196*2b24ab6bSSebastien Roy salen = ik->iptun_kparam_raddr.ss_family == AF_INET ? 197*2b24ab6bSSebastien Roy sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 198*2b24ab6bSSebastien Roy if (getnameinfo((const struct sockaddr *) 199*2b24ab6bSSebastien Roy &ik->iptun_kparam_raddr, salen, params->iptun_param_raddr, 200*2b24ab6bSSebastien Roy sizeof (params->iptun_param_raddr), NULL, 0, 201*2b24ab6bSSebastien Roy NI_NUMERICHOST) != 0) { 202*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADIPTUNRADDR); 203*2b24ab6bSSebastien Roy } 204*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_RADDR; 205*2b24ab6bSSebastien Roy } 206*2b24ab6bSSebastien Roy 207*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) { 208*2b24ab6bSSebastien Roy params->iptun_param_secinfo = ik->iptun_kparam_secinfo; 209*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_SECINFO; 210*2b24ab6bSSebastien Roy } 211*2b24ab6bSSebastien Roy 212*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT) 213*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_IMPLICIT; 214*2b24ab6bSSebastien Roy 215*2b24ab6bSSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_IPSECPOL) 216*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_IPSECPOL; 217*2b24ab6bSSebastien Roy 218*2b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 219*2b24ab6bSSebastien Roy } 220*2b24ab6bSSebastien Roy 221*2b24ab6bSSebastien Roy dladm_status_t 222*2b24ab6bSSebastien Roy i_iptun_get_sysparams(dladm_handle_t handle, iptun_params_t *params) 223*2b24ab6bSSebastien Roy { 224*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 225*2b24ab6bSSebastien Roy iptun_kparams_t ik; 226*2b24ab6bSSebastien Roy 227*2b24ab6bSSebastien Roy ik.iptun_kparam_linkid = params->iptun_param_linkid; 228*2b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_INFO, &ik); 229*2b24ab6bSSebastien Roy if (status == DLADM_STATUS_OK) 230*2b24ab6bSSebastien Roy status = i_iptun_params(&ik, params); 231*2b24ab6bSSebastien Roy return (status); 232*2b24ab6bSSebastien Roy } 233*2b24ab6bSSebastien Roy 234*2b24ab6bSSebastien Roy /* 235*2b24ab6bSSebastien Roy * Read tunnel parameters from persistent storage. Note that the tunnel type 236*2b24ab6bSSebastien Roy * is the only thing which must always be in the configuratioh. All other 237*2b24ab6bSSebastien Roy * parameters (currently the source and destination addresses) may or may not 238*2b24ab6bSSebastien Roy * have been configured, and therefore may not have been set. 239*2b24ab6bSSebastien Roy */ 240*2b24ab6bSSebastien Roy static dladm_status_t 241*2b24ab6bSSebastien Roy i_iptun_get_dbparams(dladm_handle_t handle, iptun_params_t *params) 242*2b24ab6bSSebastien Roy { 243*2b24ab6bSSebastien Roy dladm_status_t status; 244*2b24ab6bSSebastien Roy dladm_conf_t conf; 245*2b24ab6bSSebastien Roy datalink_class_t class; 246*2b24ab6bSSebastien Roy uint64_t temp; 247*2b24ab6bSSebastien Roy 248*2b24ab6bSSebastien Roy /* First, make sure that this is an IP tunnel. */ 249*2b24ab6bSSebastien Roy if ((status = dladm_datalink_id2info(handle, params->iptun_param_linkid, 250*2b24ab6bSSebastien Roy NULL, &class, NULL, NULL, 0)) != DLADM_STATUS_OK) 251*2b24ab6bSSebastien Roy return (status); 252*2b24ab6bSSebastien Roy if (class != DATALINK_CLASS_IPTUN) 253*2b24ab6bSSebastien Roy return (DLADM_STATUS_LINKINVAL); 254*2b24ab6bSSebastien Roy 255*2b24ab6bSSebastien Roy status = dladm_read_conf(handle, params->iptun_param_linkid, &conf); 256*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 257*2b24ab6bSSebastien Roy return (status); 258*2b24ab6bSSebastien Roy 259*2b24ab6bSSebastien Roy params->iptun_param_flags = 0; 260*2b24ab6bSSebastien Roy 261*2b24ab6bSSebastien Roy if ((status = dladm_get_conf_field(handle, conf, IPTUN_CONF_TYPE, &temp, 262*2b24ab6bSSebastien Roy sizeof (temp))) != DLADM_STATUS_OK) 263*2b24ab6bSSebastien Roy goto done; 264*2b24ab6bSSebastien Roy params->iptun_param_type = (iptun_type_t)temp; 265*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_TYPE; 266*2b24ab6bSSebastien Roy 267*2b24ab6bSSebastien Roy if (dladm_get_conf_field(handle, conf, IPTUN_CONF_LADDR, 268*2b24ab6bSSebastien Roy params->iptun_param_laddr, sizeof (params->iptun_param_laddr)) == 269*2b24ab6bSSebastien Roy DLADM_STATUS_OK) 270*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_LADDR; 271*2b24ab6bSSebastien Roy 272*2b24ab6bSSebastien Roy if (dladm_get_conf_field(handle, conf, IPTUN_CONF_RADDR, 273*2b24ab6bSSebastien Roy params->iptun_param_raddr, sizeof (params->iptun_param_raddr)) == 274*2b24ab6bSSebastien Roy DLADM_STATUS_OK) 275*2b24ab6bSSebastien Roy params->iptun_param_flags |= IPTUN_PARAM_RADDR; 276*2b24ab6bSSebastien Roy 277*2b24ab6bSSebastien Roy done: 278*2b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 279*2b24ab6bSSebastien Roy return (status); 280*2b24ab6bSSebastien Roy } 281*2b24ab6bSSebastien Roy 282*2b24ab6bSSebastien Roy static dladm_status_t 283*2b24ab6bSSebastien Roy i_iptun_create_sys(dladm_handle_t handle, iptun_params_t *params) 284*2b24ab6bSSebastien Roy { 285*2b24ab6bSSebastien Roy iptun_kparams_t ik; 286*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 287*2b24ab6bSSebastien Roy 288*2b24ab6bSSebastien Roy /* The tunnel type is required for creation. */ 289*2b24ab6bSSebastien Roy if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE)) 290*2b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPEREQD); 291*2b24ab6bSSebastien Roy 292*2b24ab6bSSebastien Roy if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK) 293*2b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_CREATE, &ik); 294*2b24ab6bSSebastien Roy return (status); 295*2b24ab6bSSebastien Roy } 296*2b24ab6bSSebastien Roy 297*2b24ab6bSSebastien Roy static dladm_status_t 298*2b24ab6bSSebastien Roy i_iptun_create_db(dladm_handle_t handle, const char *name, 299*2b24ab6bSSebastien Roy iptun_params_t *params, uint32_t media) 300*2b24ab6bSSebastien Roy { 301*2b24ab6bSSebastien Roy dladm_conf_t conf; 302*2b24ab6bSSebastien Roy dladm_status_t status; 303*2b24ab6bSSebastien Roy uint64_t storage; 304*2b24ab6bSSebastien Roy 305*2b24ab6bSSebastien Roy status = dladm_create_conf(handle, name, params->iptun_param_linkid, 306*2b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, media, &conf); 307*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 308*2b24ab6bSSebastien Roy return (status); 309*2b24ab6bSSebastien Roy 310*2b24ab6bSSebastien Roy assert(params->iptun_param_flags & IPTUN_PARAM_TYPE); 311*2b24ab6bSSebastien Roy storage = params->iptun_param_type; 312*2b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_TYPE, 313*2b24ab6bSSebastien Roy DLADM_TYPE_UINT64, &storage); 314*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 315*2b24ab6bSSebastien Roy goto done; 316*2b24ab6bSSebastien Roy 317*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 318*2b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR, 319*2b24ab6bSSebastien Roy DLADM_TYPE_STR, params->iptun_param_laddr); 320*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 321*2b24ab6bSSebastien Roy goto done; 322*2b24ab6bSSebastien Roy } 323*2b24ab6bSSebastien Roy 324*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 325*2b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR, 326*2b24ab6bSSebastien Roy DLADM_TYPE_STR, params->iptun_param_raddr); 327*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 328*2b24ab6bSSebastien Roy goto done; 329*2b24ab6bSSebastien Roy } 330*2b24ab6bSSebastien Roy 331*2b24ab6bSSebastien Roy status = dladm_write_conf(handle, conf); 332*2b24ab6bSSebastien Roy 333*2b24ab6bSSebastien Roy done: 334*2b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 335*2b24ab6bSSebastien Roy return (status); 336*2b24ab6bSSebastien Roy } 337*2b24ab6bSSebastien Roy 338*2b24ab6bSSebastien Roy static dladm_status_t 339*2b24ab6bSSebastien Roy i_iptun_delete_sys(dladm_handle_t handle, datalink_id_t linkid) 340*2b24ab6bSSebastien Roy { 341*2b24ab6bSSebastien Roy dladm_status_t status; 342*2b24ab6bSSebastien Roy 343*2b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_DELETE, &linkid); 344*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 345*2b24ab6bSSebastien Roy return (status); 346*2b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_ACTIVE); 347*2b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 348*2b24ab6bSSebastien Roy } 349*2b24ab6bSSebastien Roy 350*2b24ab6bSSebastien Roy static dladm_status_t 351*2b24ab6bSSebastien Roy i_iptun_modify_sys(dladm_handle_t handle, const iptun_params_t *params) 352*2b24ab6bSSebastien Roy { 353*2b24ab6bSSebastien Roy iptun_kparams_t ik; 354*2b24ab6bSSebastien Roy dladm_status_t status; 355*2b24ab6bSSebastien Roy 356*2b24ab6bSSebastien Roy if ((status = i_iptun_kparams(handle, params, &ik)) == DLADM_STATUS_OK) 357*2b24ab6bSSebastien Roy status = i_iptun_ioctl(handle, IPTUN_MODIFY, &ik); 358*2b24ab6bSSebastien Roy return (status); 359*2b24ab6bSSebastien Roy } 360*2b24ab6bSSebastien Roy 361*2b24ab6bSSebastien Roy static dladm_status_t 362*2b24ab6bSSebastien Roy i_iptun_modify_db(dladm_handle_t handle, const iptun_params_t *params) 363*2b24ab6bSSebastien Roy { 364*2b24ab6bSSebastien Roy dladm_conf_t conf; 365*2b24ab6bSSebastien Roy dladm_status_t status; 366*2b24ab6bSSebastien Roy 367*2b24ab6bSSebastien Roy assert(params->iptun_param_flags & 368*2b24ab6bSSebastien Roy (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)); 369*2b24ab6bSSebastien Roy 370*2b24ab6bSSebastien Roy /* 371*2b24ab6bSSebastien Roy * The only parameters that can be modified persistently are the local 372*2b24ab6bSSebastien Roy * and remote addresses. 373*2b24ab6bSSebastien Roy */ 374*2b24ab6bSSebastien Roy if (params->iptun_param_flags & ~(IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR)) 375*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 376*2b24ab6bSSebastien Roy 377*2b24ab6bSSebastien Roy status = dladm_read_conf(handle, params->iptun_param_linkid, &conf); 378*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 379*2b24ab6bSSebastien Roy return (status); 380*2b24ab6bSSebastien Roy 381*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_LADDR) { 382*2b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_LADDR, 383*2b24ab6bSSebastien Roy DLADM_TYPE_STR, (void *)params->iptun_param_laddr); 384*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 385*2b24ab6bSSebastien Roy goto done; 386*2b24ab6bSSebastien Roy } 387*2b24ab6bSSebastien Roy 388*2b24ab6bSSebastien Roy if (params->iptun_param_flags & IPTUN_PARAM_RADDR) { 389*2b24ab6bSSebastien Roy status = dladm_set_conf_field(handle, conf, IPTUN_CONF_RADDR, 390*2b24ab6bSSebastien Roy DLADM_TYPE_STR, (void *)params->iptun_param_raddr); 391*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 392*2b24ab6bSSebastien Roy goto done; 393*2b24ab6bSSebastien Roy } 394*2b24ab6bSSebastien Roy 395*2b24ab6bSSebastien Roy status = dladm_write_conf(handle, conf); 396*2b24ab6bSSebastien Roy 397*2b24ab6bSSebastien Roy done: 398*2b24ab6bSSebastien Roy dladm_destroy_conf(handle, conf); 399*2b24ab6bSSebastien Roy return (status); 400*2b24ab6bSSebastien Roy } 401*2b24ab6bSSebastien Roy 402*2b24ab6bSSebastien Roy dladm_status_t 403*2b24ab6bSSebastien Roy dladm_iptun_create(dladm_handle_t handle, const char *name, 404*2b24ab6bSSebastien Roy iptun_params_t *params, uint32_t flags) 405*2b24ab6bSSebastien Roy { 406*2b24ab6bSSebastien Roy dladm_status_t status; 407*2b24ab6bSSebastien Roy uint32_t linkmgmt_flags = flags; 408*2b24ab6bSSebastien Roy uint32_t media; 409*2b24ab6bSSebastien Roy 410*2b24ab6bSSebastien Roy if (!(params->iptun_param_flags & IPTUN_PARAM_TYPE)) 411*2b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPEREQD); 412*2b24ab6bSSebastien Roy 413*2b24ab6bSSebastien Roy switch (params->iptun_param_type) { 414*2b24ab6bSSebastien Roy case IPTUN_TYPE_IPV4: 415*2b24ab6bSSebastien Roy media = DL_IPV4; 416*2b24ab6bSSebastien Roy break; 417*2b24ab6bSSebastien Roy case IPTUN_TYPE_IPV6: 418*2b24ab6bSSebastien Roy media = DL_IPV6; 419*2b24ab6bSSebastien Roy break; 420*2b24ab6bSSebastien Roy case IPTUN_TYPE_6TO4: 421*2b24ab6bSSebastien Roy media = DL_6TO4; 422*2b24ab6bSSebastien Roy break; 423*2b24ab6bSSebastien Roy default: 424*2b24ab6bSSebastien Roy return (DLADM_STATUS_IPTUNTYPE); 425*2b24ab6bSSebastien Roy } 426*2b24ab6bSSebastien Roy 427*2b24ab6bSSebastien Roy status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_IPTUN, 428*2b24ab6bSSebastien Roy media, linkmgmt_flags, ¶ms->iptun_param_linkid); 429*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 430*2b24ab6bSSebastien Roy return (status); 431*2b24ab6bSSebastien Roy 432*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 433*2b24ab6bSSebastien Roy status = i_iptun_create_db(handle, name, params, media); 434*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 435*2b24ab6bSSebastien Roy goto done; 436*2b24ab6bSSebastien Roy } 437*2b24ab6bSSebastien Roy 438*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 439*2b24ab6bSSebastien Roy status = i_iptun_create_sys(handle, params); 440*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) { 441*2b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, 442*2b24ab6bSSebastien Roy params->iptun_param_linkid); 443*2b24ab6bSSebastien Roy } 444*2b24ab6bSSebastien Roy } 445*2b24ab6bSSebastien Roy 446*2b24ab6bSSebastien Roy done: 447*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 448*2b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, 449*2b24ab6bSSebastien Roy params->iptun_param_linkid, flags); 450*2b24ab6bSSebastien Roy } 451*2b24ab6bSSebastien Roy return (status); 452*2b24ab6bSSebastien Roy } 453*2b24ab6bSSebastien Roy 454*2b24ab6bSSebastien Roy dladm_status_t 455*2b24ab6bSSebastien Roy dladm_iptun_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 456*2b24ab6bSSebastien Roy { 457*2b24ab6bSSebastien Roy dladm_status_t status; 458*2b24ab6bSSebastien Roy datalink_class_t class; 459*2b24ab6bSSebastien Roy 460*2b24ab6bSSebastien Roy /* First, make sure that this is an IP tunnel. */ 461*2b24ab6bSSebastien Roy if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 462*2b24ab6bSSebastien Roy NULL, 0)) != DLADM_STATUS_OK) 463*2b24ab6bSSebastien Roy return (status); 464*2b24ab6bSSebastien Roy if (class != DATALINK_CLASS_IPTUN) 465*2b24ab6bSSebastien Roy return (DLADM_STATUS_LINKINVAL); 466*2b24ab6bSSebastien Roy 467*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 468*2b24ab6bSSebastien Roy /* 469*2b24ab6bSSebastien Roy * Note that if i_iptun_delete_sys() fails with 470*2b24ab6bSSebastien Roy * DLADM_STATUS_NOTFOUND and the caller also wishes to delete 471*2b24ab6bSSebastien Roy * the persistent configuration, we still fall through to the 472*2b24ab6bSSebastien Roy * DLADM_OPT_PERSIST case in case the tunnel only exists 473*2b24ab6bSSebastien Roy * persistently. 474*2b24ab6bSSebastien Roy */ 475*2b24ab6bSSebastien Roy status = i_iptun_delete_sys(handle, linkid); 476*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && 477*2b24ab6bSSebastien Roy (status != DLADM_STATUS_NOTFOUND || 478*2b24ab6bSSebastien Roy !(flags & DLADM_OPT_PERSIST))) 479*2b24ab6bSSebastien Roy return (status); 480*2b24ab6bSSebastien Roy } 481*2b24ab6bSSebastien Roy 482*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 483*2b24ab6bSSebastien Roy (void) dladm_remove_conf(handle, linkid); 484*2b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, 485*2b24ab6bSSebastien Roy DLADM_OPT_PERSIST); 486*2b24ab6bSSebastien Roy } 487*2b24ab6bSSebastien Roy return (DLADM_STATUS_OK); 488*2b24ab6bSSebastien Roy } 489*2b24ab6bSSebastien Roy 490*2b24ab6bSSebastien Roy dladm_status_t 491*2b24ab6bSSebastien Roy dladm_iptun_modify(dladm_handle_t handle, const iptun_params_t *params, 492*2b24ab6bSSebastien Roy uint32_t flags) 493*2b24ab6bSSebastien Roy { 494*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 495*2b24ab6bSSebastien Roy iptun_params_t old_params; 496*2b24ab6bSSebastien Roy 497*2b24ab6bSSebastien Roy /* 498*2b24ab6bSSebastien Roy * We can only modify the tunnel source, tunnel destination, or IPsec 499*2b24ab6bSSebastien Roy * policy. 500*2b24ab6bSSebastien Roy */ 501*2b24ab6bSSebastien Roy if (!(params->iptun_param_flags & 502*2b24ab6bSSebastien Roy (IPTUN_PARAM_LADDR|IPTUN_PARAM_RADDR|IPTUN_PARAM_SECINFO))) 503*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 504*2b24ab6bSSebastien Roy 505*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_PERSIST) { 506*2b24ab6bSSebastien Roy /* 507*2b24ab6bSSebastien Roy * Before we change the database, save the old configuration 508*2b24ab6bSSebastien Roy * so that we can revert back if an error occurs. 509*2b24ab6bSSebastien Roy */ 510*2b24ab6bSSebastien Roy old_params.iptun_param_linkid = params->iptun_param_linkid; 511*2b24ab6bSSebastien Roy status = i_iptun_get_dbparams(handle, &old_params); 512*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 513*2b24ab6bSSebastien Roy return (status); 514*2b24ab6bSSebastien Roy /* we'll only need to revert the parameters being modified */ 515*2b24ab6bSSebastien Roy old_params.iptun_param_flags = params->iptun_param_flags; 516*2b24ab6bSSebastien Roy 517*2b24ab6bSSebastien Roy status = i_iptun_modify_db(handle, params); 518*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 519*2b24ab6bSSebastien Roy return (status); 520*2b24ab6bSSebastien Roy } 521*2b24ab6bSSebastien Roy 522*2b24ab6bSSebastien Roy if (flags & DLADM_OPT_ACTIVE) { 523*2b24ab6bSSebastien Roy status = i_iptun_modify_sys(handle, params); 524*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST)) { 525*2b24ab6bSSebastien Roy (void) i_iptun_modify_db(handle, &old_params); 526*2b24ab6bSSebastien Roy } 527*2b24ab6bSSebastien Roy } 528*2b24ab6bSSebastien Roy 529*2b24ab6bSSebastien Roy return (status); 530*2b24ab6bSSebastien Roy } 531*2b24ab6bSSebastien Roy 532*2b24ab6bSSebastien Roy dladm_status_t 533*2b24ab6bSSebastien Roy dladm_iptun_getparams(dladm_handle_t handle, iptun_params_t *params, 534*2b24ab6bSSebastien Roy uint32_t flags) 535*2b24ab6bSSebastien Roy { 536*2b24ab6bSSebastien Roy if (flags == DLADM_OPT_ACTIVE) 537*2b24ab6bSSebastien Roy return (i_iptun_get_sysparams(handle, params)); 538*2b24ab6bSSebastien Roy else if (flags == DLADM_OPT_PERSIST) 539*2b24ab6bSSebastien Roy return (i_iptun_get_dbparams(handle, params)); 540*2b24ab6bSSebastien Roy else 541*2b24ab6bSSebastien Roy return (DLADM_STATUS_BADARG); 542*2b24ab6bSSebastien Roy } 543*2b24ab6bSSebastien Roy 544*2b24ab6bSSebastien Roy static int 545*2b24ab6bSSebastien Roy i_iptun_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 546*2b24ab6bSSebastien Roy { 547*2b24ab6bSSebastien Roy dladm_status_t *statusp = arg; 548*2b24ab6bSSebastien Roy dladm_status_t status; 549*2b24ab6bSSebastien Roy iptun_params_t params; 550*2b24ab6bSSebastien Roy boolean_t id_up = B_FALSE; 551*2b24ab6bSSebastien Roy 552*2b24ab6bSSebastien Roy status = dladm_up_datalink_id(handle, linkid); 553*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) 554*2b24ab6bSSebastien Roy goto done; 555*2b24ab6bSSebastien Roy id_up = B_TRUE; 556*2b24ab6bSSebastien Roy 557*2b24ab6bSSebastien Roy (void) memset(¶ms, 0, sizeof (params)); 558*2b24ab6bSSebastien Roy 559*2b24ab6bSSebastien Roy params.iptun_param_linkid = linkid; 560*2b24ab6bSSebastien Roy if ((status = i_iptun_get_dbparams(handle, ¶ms)) == DLADM_STATUS_OK) 561*2b24ab6bSSebastien Roy status = i_iptun_create_sys(handle, ¶ms); 562*2b24ab6bSSebastien Roy done: 563*2b24ab6bSSebastien Roy if (statusp != NULL) 564*2b24ab6bSSebastien Roy *statusp = status; 565*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK && id_up) { 566*2b24ab6bSSebastien Roy (void) dladm_destroy_datalink_id(handle, linkid, 567*2b24ab6bSSebastien Roy DLADM_OPT_ACTIVE); 568*2b24ab6bSSebastien Roy } 569*2b24ab6bSSebastien Roy return (DLADM_WALK_CONTINUE); 570*2b24ab6bSSebastien Roy } 571*2b24ab6bSSebastien Roy 572*2b24ab6bSSebastien Roy static int 573*2b24ab6bSSebastien Roy i_iptun_down(dladm_handle_t handle, datalink_id_t linkid, void *arg) 574*2b24ab6bSSebastien Roy { 575*2b24ab6bSSebastien Roy dladm_status_t *statusp = arg; 576*2b24ab6bSSebastien Roy dladm_status_t status; 577*2b24ab6bSSebastien Roy 578*2b24ab6bSSebastien Roy status = i_iptun_delete_sys(handle, linkid); 579*2b24ab6bSSebastien Roy if (statusp != NULL) 580*2b24ab6bSSebastien Roy *statusp = status; 581*2b24ab6bSSebastien Roy return (DLADM_WALK_CONTINUE); 582*2b24ab6bSSebastien Roy } 583*2b24ab6bSSebastien Roy 584*2b24ab6bSSebastien Roy /* ARGSUSED */ 585*2b24ab6bSSebastien Roy dladm_status_t 586*2b24ab6bSSebastien Roy dladm_iptun_up(dladm_handle_t handle, datalink_id_t linkid) 587*2b24ab6bSSebastien Roy { 588*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 589*2b24ab6bSSebastien Roy 590*2b24ab6bSSebastien Roy if (linkid == DATALINK_ALL_LINKID) { 591*2b24ab6bSSebastien Roy (void) dladm_walk_datalink_id(i_iptun_up, handle, NULL, 592*2b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 593*2b24ab6bSSebastien Roy DLADM_OPT_PERSIST); 594*2b24ab6bSSebastien Roy } else { 595*2b24ab6bSSebastien Roy (void) i_iptun_up(handle, linkid, &status); 596*2b24ab6bSSebastien Roy } 597*2b24ab6bSSebastien Roy return (status); 598*2b24ab6bSSebastien Roy } 599*2b24ab6bSSebastien Roy 600*2b24ab6bSSebastien Roy dladm_status_t 601*2b24ab6bSSebastien Roy dladm_iptun_down(dladm_handle_t handle, datalink_id_t linkid) 602*2b24ab6bSSebastien Roy { 603*2b24ab6bSSebastien Roy dladm_status_t status = DLADM_STATUS_OK; 604*2b24ab6bSSebastien Roy 605*2b24ab6bSSebastien Roy if (linkid == DATALINK_ALL_LINKID) { 606*2b24ab6bSSebastien Roy (void) dladm_walk_datalink_id(i_iptun_down, handle, NULL, 607*2b24ab6bSSebastien Roy DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 608*2b24ab6bSSebastien Roy DLADM_OPT_ACTIVE); 609*2b24ab6bSSebastien Roy } else { 610*2b24ab6bSSebastien Roy (void) i_iptun_down(handle, linkid, &status); 611*2b24ab6bSSebastien Roy } 612*2b24ab6bSSebastien Roy return (status); 613*2b24ab6bSSebastien Roy } 614*2b24ab6bSSebastien Roy 615*2b24ab6bSSebastien Roy dladm_status_t 616*2b24ab6bSSebastien Roy dladm_iptun_set6to4relay(dladm_handle_t handle, struct in_addr *relay) 617*2b24ab6bSSebastien Roy { 618*2b24ab6bSSebastien Roy return (i_iptun_ioctl(handle, IPTUN_SET_6TO4RELAY, relay)); 619*2b24ab6bSSebastien Roy } 620*2b24ab6bSSebastien Roy 621*2b24ab6bSSebastien Roy dladm_status_t 622*2b24ab6bSSebastien Roy dladm_iptun_get6to4relay(dladm_handle_t handle, struct in_addr *relay) 623*2b24ab6bSSebastien Roy { 624*2b24ab6bSSebastien Roy return (i_iptun_ioctl(handle, IPTUN_GET_6TO4RELAY, relay)); 625*2b24ab6bSSebastien Roy } 626