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 /* 27 * IP Tunneling Driver 28 * 29 * As viewed from the top, this module is a GLDv3 driver that consumes the 30 * mac driver interfaces. It implements the logic for various forms of IP 31 * (IPv4 or IPv6) encapsulation within IP (IPv4 or IPv6). 32 */ 33 34 #include <sys/file.h> 35 #include <sys/list.h> 36 #include "iptun_impl.h" 37 38 #define IPTUN_LINKINFO "IP tunneling driver" 39 #define IPTUN_HASHSZ 67 40 41 dev_info_t *iptun_dip; 42 ldi_ident_t iptun_ldi_ident; 43 44 static int iptun_attach(dev_info_t *, ddi_attach_cmd_t); 45 static int iptun_detach(dev_info_t *, ddi_detach_cmd_t); 46 static int iptun_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 47 static int iptun_constructor(void *, void *, int); 48 static void iptun_destructor(void *, void *); 49 50 DDI_DEFINE_STREAM_OPS(iptun_dev_ops, nulldev, nulldev, iptun_attach, 51 iptun_detach, nodev, iptun_getinfo, D_MP, NULL, ddi_quiesce_not_supported); 52 53 static struct modldrv iptun_modldrv = { 54 &mod_driverops, 55 IPTUN_LINKINFO, 56 &iptun_dev_ops 57 }; 58 59 static struct modlinkage iptun_modlinkage = { 60 MODREV_1, 61 &iptun_modldrv, 62 NULL 63 }; 64 65 /* 66 * Initialize the tunnel stack instance. 67 */ 68 /* ARGSUSED */ 69 static void * 70 iptun_stack_init(netstackid_t stackid, netstack_t *ns) 71 { 72 iptun_stack_t *iptuns; 73 74 iptuns = kmem_zalloc(sizeof (*iptuns), KM_SLEEP); 75 iptuns->iptuns_netstack = ns; 76 mutex_init(&iptuns->iptuns_lock, NULL, MUTEX_DEFAULT, NULL); 77 list_create(&iptuns->iptuns_iptunlist, sizeof (iptun_t), 78 offsetof(iptun_t, iptun_link)); 79 80 return (iptuns); 81 } 82 83 /* ARGSUSED */ 84 static void 85 iptun_stack_shutdown(netstackid_t stackid, void *arg) 86 { 87 iptun_stack_t *iptuns = arg; 88 iptun_t *iptun; 89 datalink_id_t linkid; 90 91 /* note that iptun_delete() removes iptun from the list */ 92 while ((iptun = list_head(&iptuns->iptuns_iptunlist)) != NULL) { 93 linkid = iptun->iptun_linkid; 94 (void) iptun_delete(linkid, iptun->iptun_cred); 95 (void) dls_mgmt_destroy(linkid, B_FALSE); 96 } 97 if (iptuns->iptuns_g_q != NULL) 98 (void) ldi_close(iptuns->iptuns_g_q_lh, FWRITE|FREAD, CRED()); 99 } 100 101 /* 102 * Free the tunnel stack instance. 103 */ 104 /* ARGSUSED */ 105 static void 106 iptun_stack_fini(netstackid_t stackid, void *arg) 107 { 108 iptun_stack_t *iptuns = arg; 109 110 list_destroy(&iptuns->iptuns_iptunlist); 111 mutex_destroy(&iptuns->iptuns_lock); 112 kmem_free(iptuns, sizeof (*iptuns)); 113 } 114 115 static void 116 iptun_fini(void) 117 { 118 ddi_taskq_destroy(iptun_taskq); 119 mac_fini_ops(&iptun_dev_ops); 120 ldi_ident_release(iptun_ldi_ident); 121 mod_hash_destroy_idhash(iptun_hash); 122 kmem_cache_destroy(iptun_cache); 123 } 124 125 int 126 _init(void) 127 { 128 int rc; 129 130 rc = ldi_ident_from_mod(&iptun_modlinkage, &iptun_ldi_ident); 131 if (rc != 0) 132 return (rc); 133 134 iptun_cache = kmem_cache_create("iptun_cache", sizeof (iptun_t), 0, 135 iptun_constructor, iptun_destructor, NULL, NULL, NULL, 0); 136 if (iptun_cache == NULL) { 137 ldi_ident_release(iptun_ldi_ident); 138 return (ENOMEM); 139 } 140 141 iptun_taskq = ddi_taskq_create(NULL, "iptun_taskq", 1, 142 TASKQ_DEFAULTPRI, 0); 143 if (iptun_taskq == NULL) { 144 ldi_ident_release(iptun_ldi_ident); 145 kmem_cache_destroy(iptun_cache); 146 return (ENOMEM); 147 } 148 149 iptun_hash = mod_hash_create_idhash("iptun_hash", IPTUN_HASHSZ, 150 mod_hash_null_valdtor); 151 152 mac_init_ops(&iptun_dev_ops, IPTUN_DRIVER_NAME); 153 154 if ((rc = mod_install(&iptun_modlinkage)) != 0) 155 iptun_fini(); 156 return (rc); 157 } 158 159 int 160 _fini(void) 161 { 162 int rc; 163 164 if ((rc = mod_remove(&iptun_modlinkage)) == 0) 165 iptun_fini(); 166 return (rc); 167 } 168 169 int 170 _info(struct modinfo *modinfop) 171 { 172 return (mod_info(&iptun_modlinkage, modinfop)); 173 } 174 175 static int 176 iptun_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 177 { 178 switch (cmd) { 179 case DDI_ATTACH: 180 if (ddi_get_instance(dip) != 0 || iptun_ioc_init() != 0) 181 return (DDI_FAILURE); 182 iptun_dip = dip; 183 netstack_register(NS_IPTUN, iptun_stack_init, 184 iptun_stack_shutdown, iptun_stack_fini); 185 return (DDI_SUCCESS); 186 187 default: 188 return (DDI_FAILURE); 189 } 190 } 191 192 /* ARGSUSED */ 193 static int 194 iptun_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 195 { 196 switch (cmd) { 197 case DDI_DETACH: 198 /* 199 * We prevent the pseudo device from detaching (and thus the 200 * driver from unloading) when there are tunnels configured by 201 * consulting iptun_count(). We don't need to hold a lock 202 * here because the tunnel count is only changed when a tunnel 203 * is created or deleted, which can't happen while the detach 204 * routine is running (the ioctl path calls 205 * ddi_hold_devi_by_instance() in dld's drv_ioctl(), and the 206 * /dev/net implicit path has the device open). 207 */ 208 if (iptun_count() > 0) 209 return (DDI_FAILURE); 210 netstack_unregister(NS_IPTUN); 211 iptun_dip = NULL; 212 iptun_ioc_fini(); 213 return (DDI_SUCCESS); 214 215 default: 216 return (DDI_FAILURE); 217 } 218 } 219 220 /* ARGSUSED */ 221 static int 222 iptun_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 223 { 224 switch (infocmd) { 225 case DDI_INFO_DEVT2DEVINFO: 226 *result = iptun_dip; 227 return (DDI_SUCCESS); 228 case DDI_INFO_DEVT2INSTANCE: 229 *result = NULL; 230 return (DDI_SUCCESS); 231 } 232 return (DDI_FAILURE); 233 } 234 235 /* ARGSUSED */ 236 static int 237 iptun_constructor(void *buf, void *cdrarg, int kmflags) 238 { 239 iptun_t *iptun = buf; 240 241 bzero(iptun, sizeof (*iptun)); 242 mutex_init(&iptun->iptun_lock, NULL, MUTEX_DEFAULT, NULL); 243 cv_init(&iptun->iptun_upcall_cv, NULL, CV_DRIVER, NULL); 244 cv_init(&iptun->iptun_enter_cv, NULL, CV_DRIVER, NULL); 245 246 return (0); 247 } 248 249 /* ARGSUSED */ 250 static void 251 iptun_destructor(void *buf, void *cdrarg) 252 { 253 iptun_t *iptun = buf; 254 255 /* This iptun_t must not still be in use. */ 256 ASSERT(!(iptun->iptun_flags & (IPTUN_BOUND|IPTUN_MAC_REGISTERED| 257 IPTUN_MAC_STARTED|IPTUN_HASH_INSERTED|IPTUN_UPCALL_PENDING))); 258 259 mutex_destroy(&iptun->iptun_lock); 260 cv_destroy(&iptun->iptun_upcall_cv); 261 } 262