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 /* 222b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232b24ab6bSSebastien Roy * Use is subject to license terms. 242b24ab6bSSebastien Roy */ 252b24ab6bSSebastien Roy 262b24ab6bSSebastien Roy /* 272b24ab6bSSebastien Roy * IP Tunneling Driver 282b24ab6bSSebastien Roy * 292b24ab6bSSebastien Roy * As viewed from the top, this module is a GLDv3 driver that consumes the 302b24ab6bSSebastien Roy * mac driver interfaces. It implements the logic for various forms of IP 312b24ab6bSSebastien Roy * (IPv4 or IPv6) encapsulation within IP (IPv4 or IPv6). 322b24ab6bSSebastien Roy */ 332b24ab6bSSebastien Roy 342b24ab6bSSebastien Roy #include <sys/file.h> 352b24ab6bSSebastien Roy #include <sys/list.h> 362b24ab6bSSebastien Roy #include "iptun_impl.h" 372b24ab6bSSebastien Roy 382b24ab6bSSebastien Roy #define IPTUN_LINKINFO "IP tunneling driver" 392b24ab6bSSebastien Roy #define IPTUN_HASHSZ 67 402b24ab6bSSebastien Roy 412b24ab6bSSebastien Roy dev_info_t *iptun_dip; 422b24ab6bSSebastien Roy ldi_ident_t iptun_ldi_ident; 432b24ab6bSSebastien Roy 442b24ab6bSSebastien Roy static int iptun_attach(dev_info_t *, ddi_attach_cmd_t); 452b24ab6bSSebastien Roy static int iptun_detach(dev_info_t *, ddi_detach_cmd_t); 462b24ab6bSSebastien Roy static int iptun_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 472b24ab6bSSebastien Roy static int iptun_constructor(void *, void *, int); 482b24ab6bSSebastien Roy static void iptun_destructor(void *, void *); 492b24ab6bSSebastien Roy 502b24ab6bSSebastien Roy DDI_DEFINE_STREAM_OPS(iptun_dev_ops, nulldev, nulldev, iptun_attach, 512b24ab6bSSebastien Roy iptun_detach, nodev, iptun_getinfo, D_MP, NULL, ddi_quiesce_not_supported); 522b24ab6bSSebastien Roy 532b24ab6bSSebastien Roy static struct modldrv iptun_modldrv = { 542b24ab6bSSebastien Roy &mod_driverops, 552b24ab6bSSebastien Roy IPTUN_LINKINFO, 562b24ab6bSSebastien Roy &iptun_dev_ops 572b24ab6bSSebastien Roy }; 582b24ab6bSSebastien Roy 592b24ab6bSSebastien Roy static struct modlinkage iptun_modlinkage = { 602b24ab6bSSebastien Roy MODREV_1, 612b24ab6bSSebastien Roy &iptun_modldrv, 622b24ab6bSSebastien Roy NULL 632b24ab6bSSebastien Roy }; 642b24ab6bSSebastien Roy 652b24ab6bSSebastien Roy /* 662b24ab6bSSebastien Roy * Initialize the tunnel stack instance. 672b24ab6bSSebastien Roy */ 682b24ab6bSSebastien Roy /* ARGSUSED */ 692b24ab6bSSebastien Roy static void * 702b24ab6bSSebastien Roy iptun_stack_init(netstackid_t stackid, netstack_t *ns) 712b24ab6bSSebastien Roy { 722b24ab6bSSebastien Roy iptun_stack_t *iptuns; 732b24ab6bSSebastien Roy 742b24ab6bSSebastien Roy iptuns = kmem_zalloc(sizeof (*iptuns), KM_SLEEP); 752b24ab6bSSebastien Roy iptuns->iptuns_netstack = ns; 762b24ab6bSSebastien Roy mutex_init(&iptuns->iptuns_lock, NULL, MUTEX_DEFAULT, NULL); 772b24ab6bSSebastien Roy list_create(&iptuns->iptuns_iptunlist, sizeof (iptun_t), 782b24ab6bSSebastien Roy offsetof(iptun_t, iptun_link)); 792b24ab6bSSebastien Roy 802b24ab6bSSebastien Roy return (iptuns); 812b24ab6bSSebastien Roy } 822b24ab6bSSebastien Roy 832b24ab6bSSebastien Roy /* ARGSUSED */ 842b24ab6bSSebastien Roy static void 852b24ab6bSSebastien Roy iptun_stack_shutdown(netstackid_t stackid, void *arg) 862b24ab6bSSebastien Roy { 872b24ab6bSSebastien Roy iptun_stack_t *iptuns = arg; 882b24ab6bSSebastien Roy iptun_t *iptun; 892b24ab6bSSebastien Roy datalink_id_t linkid; 902b24ab6bSSebastien Roy 912b24ab6bSSebastien Roy /* note that iptun_delete() removes iptun from the list */ 922b24ab6bSSebastien Roy while ((iptun = list_head(&iptuns->iptuns_iptunlist)) != NULL) { 932b24ab6bSSebastien Roy linkid = iptun->iptun_linkid; 94*bd670b35SErik Nordmark (void) iptun_delete(linkid, iptun->iptun_connp->conn_cred); 952b24ab6bSSebastien Roy (void) dls_mgmt_destroy(linkid, B_FALSE); 962b24ab6bSSebastien Roy } 972b24ab6bSSebastien Roy } 982b24ab6bSSebastien Roy 992b24ab6bSSebastien Roy /* 1002b24ab6bSSebastien Roy * Free the tunnel stack instance. 1012b24ab6bSSebastien Roy */ 1022b24ab6bSSebastien Roy /* ARGSUSED */ 1032b24ab6bSSebastien Roy static void 1042b24ab6bSSebastien Roy iptun_stack_fini(netstackid_t stackid, void *arg) 1052b24ab6bSSebastien Roy { 1062b24ab6bSSebastien Roy iptun_stack_t *iptuns = arg; 1072b24ab6bSSebastien Roy 1082b24ab6bSSebastien Roy list_destroy(&iptuns->iptuns_iptunlist); 1092b24ab6bSSebastien Roy mutex_destroy(&iptuns->iptuns_lock); 1102b24ab6bSSebastien Roy kmem_free(iptuns, sizeof (*iptuns)); 1112b24ab6bSSebastien Roy } 1122b24ab6bSSebastien Roy 1132b24ab6bSSebastien Roy static void 1142b24ab6bSSebastien Roy iptun_fini(void) 1152b24ab6bSSebastien Roy { 1162b24ab6bSSebastien Roy ddi_taskq_destroy(iptun_taskq); 1172b24ab6bSSebastien Roy mac_fini_ops(&iptun_dev_ops); 1182b24ab6bSSebastien Roy ldi_ident_release(iptun_ldi_ident); 1192b24ab6bSSebastien Roy mod_hash_destroy_idhash(iptun_hash); 1202b24ab6bSSebastien Roy kmem_cache_destroy(iptun_cache); 1212b24ab6bSSebastien Roy } 1222b24ab6bSSebastien Roy 1232b24ab6bSSebastien Roy int 1242b24ab6bSSebastien Roy _init(void) 1252b24ab6bSSebastien Roy { 1262b24ab6bSSebastien Roy int rc; 1272b24ab6bSSebastien Roy 1282b24ab6bSSebastien Roy rc = ldi_ident_from_mod(&iptun_modlinkage, &iptun_ldi_ident); 1292b24ab6bSSebastien Roy if (rc != 0) 1302b24ab6bSSebastien Roy return (rc); 1312b24ab6bSSebastien Roy 1322b24ab6bSSebastien Roy iptun_cache = kmem_cache_create("iptun_cache", sizeof (iptun_t), 0, 1332b24ab6bSSebastien Roy iptun_constructor, iptun_destructor, NULL, NULL, NULL, 0); 1342b24ab6bSSebastien Roy if (iptun_cache == NULL) { 1352b24ab6bSSebastien Roy ldi_ident_release(iptun_ldi_ident); 1362b24ab6bSSebastien Roy return (ENOMEM); 1372b24ab6bSSebastien Roy } 1382b24ab6bSSebastien Roy 1392b24ab6bSSebastien Roy iptun_taskq = ddi_taskq_create(NULL, "iptun_taskq", 1, 1402b24ab6bSSebastien Roy TASKQ_DEFAULTPRI, 0); 1412b24ab6bSSebastien Roy if (iptun_taskq == NULL) { 1422b24ab6bSSebastien Roy ldi_ident_release(iptun_ldi_ident); 1432b24ab6bSSebastien Roy kmem_cache_destroy(iptun_cache); 1442b24ab6bSSebastien Roy return (ENOMEM); 1452b24ab6bSSebastien Roy } 1462b24ab6bSSebastien Roy 1472b24ab6bSSebastien Roy iptun_hash = mod_hash_create_idhash("iptun_hash", IPTUN_HASHSZ, 1482b24ab6bSSebastien Roy mod_hash_null_valdtor); 1492b24ab6bSSebastien Roy 1502b24ab6bSSebastien Roy mac_init_ops(&iptun_dev_ops, IPTUN_DRIVER_NAME); 1512b24ab6bSSebastien Roy 1522b24ab6bSSebastien Roy if ((rc = mod_install(&iptun_modlinkage)) != 0) 1532b24ab6bSSebastien Roy iptun_fini(); 1542b24ab6bSSebastien Roy return (rc); 1552b24ab6bSSebastien Roy } 1562b24ab6bSSebastien Roy 1572b24ab6bSSebastien Roy int 1582b24ab6bSSebastien Roy _fini(void) 1592b24ab6bSSebastien Roy { 1602b24ab6bSSebastien Roy int rc; 1612b24ab6bSSebastien Roy 1622b24ab6bSSebastien Roy if ((rc = mod_remove(&iptun_modlinkage)) == 0) 1632b24ab6bSSebastien Roy iptun_fini(); 1642b24ab6bSSebastien Roy return (rc); 1652b24ab6bSSebastien Roy } 1662b24ab6bSSebastien Roy 1672b24ab6bSSebastien Roy int 1682b24ab6bSSebastien Roy _info(struct modinfo *modinfop) 1692b24ab6bSSebastien Roy { 1702b24ab6bSSebastien Roy return (mod_info(&iptun_modlinkage, modinfop)); 1712b24ab6bSSebastien Roy } 1722b24ab6bSSebastien Roy 1732b24ab6bSSebastien Roy static int 1742b24ab6bSSebastien Roy iptun_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1752b24ab6bSSebastien Roy { 1762b24ab6bSSebastien Roy switch (cmd) { 1772b24ab6bSSebastien Roy case DDI_ATTACH: 1782b24ab6bSSebastien Roy if (ddi_get_instance(dip) != 0 || iptun_ioc_init() != 0) 1792b24ab6bSSebastien Roy return (DDI_FAILURE); 1802b24ab6bSSebastien Roy iptun_dip = dip; 1812b24ab6bSSebastien Roy netstack_register(NS_IPTUN, iptun_stack_init, 1822b24ab6bSSebastien Roy iptun_stack_shutdown, iptun_stack_fini); 1832b24ab6bSSebastien Roy return (DDI_SUCCESS); 1842b24ab6bSSebastien Roy 1852b24ab6bSSebastien Roy default: 1862b24ab6bSSebastien Roy return (DDI_FAILURE); 1872b24ab6bSSebastien Roy } 1882b24ab6bSSebastien Roy } 1892b24ab6bSSebastien Roy 1902b24ab6bSSebastien Roy /* ARGSUSED */ 1912b24ab6bSSebastien Roy static int 1922b24ab6bSSebastien Roy iptun_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1932b24ab6bSSebastien Roy { 1942b24ab6bSSebastien Roy switch (cmd) { 1952b24ab6bSSebastien Roy case DDI_DETACH: 1962b24ab6bSSebastien Roy /* 1972b24ab6bSSebastien Roy * We prevent the pseudo device from detaching (and thus the 1982b24ab6bSSebastien Roy * driver from unloading) when there are tunnels configured by 1992b24ab6bSSebastien Roy * consulting iptun_count(). We don't need to hold a lock 2002b24ab6bSSebastien Roy * here because the tunnel count is only changed when a tunnel 2012b24ab6bSSebastien Roy * is created or deleted, which can't happen while the detach 2022b24ab6bSSebastien Roy * routine is running (the ioctl path calls 2032b24ab6bSSebastien Roy * ddi_hold_devi_by_instance() in dld's drv_ioctl(), and the 2042b24ab6bSSebastien Roy * /dev/net implicit path has the device open). 2052b24ab6bSSebastien Roy */ 2062b24ab6bSSebastien Roy if (iptun_count() > 0) 2072b24ab6bSSebastien Roy return (DDI_FAILURE); 2082b24ab6bSSebastien Roy netstack_unregister(NS_IPTUN); 2092b24ab6bSSebastien Roy iptun_dip = NULL; 2102b24ab6bSSebastien Roy iptun_ioc_fini(); 2112b24ab6bSSebastien Roy return (DDI_SUCCESS); 2122b24ab6bSSebastien Roy 2132b24ab6bSSebastien Roy default: 2142b24ab6bSSebastien Roy return (DDI_FAILURE); 2152b24ab6bSSebastien Roy } 2162b24ab6bSSebastien Roy } 2172b24ab6bSSebastien Roy 2182b24ab6bSSebastien Roy /* ARGSUSED */ 2192b24ab6bSSebastien Roy static int 2202b24ab6bSSebastien Roy iptun_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2212b24ab6bSSebastien Roy { 2222b24ab6bSSebastien Roy switch (infocmd) { 2232b24ab6bSSebastien Roy case DDI_INFO_DEVT2DEVINFO: 2242b24ab6bSSebastien Roy *result = iptun_dip; 2252b24ab6bSSebastien Roy return (DDI_SUCCESS); 2262b24ab6bSSebastien Roy case DDI_INFO_DEVT2INSTANCE: 2272b24ab6bSSebastien Roy *result = NULL; 2282b24ab6bSSebastien Roy return (DDI_SUCCESS); 2292b24ab6bSSebastien Roy } 2302b24ab6bSSebastien Roy return (DDI_FAILURE); 2312b24ab6bSSebastien Roy } 2322b24ab6bSSebastien Roy 2332b24ab6bSSebastien Roy /* ARGSUSED */ 2342b24ab6bSSebastien Roy static int 2352b24ab6bSSebastien Roy iptun_constructor(void *buf, void *cdrarg, int kmflags) 2362b24ab6bSSebastien Roy { 2372b24ab6bSSebastien Roy iptun_t *iptun = buf; 2382b24ab6bSSebastien Roy 2392b24ab6bSSebastien Roy bzero(iptun, sizeof (*iptun)); 2402b24ab6bSSebastien Roy mutex_init(&iptun->iptun_lock, NULL, MUTEX_DEFAULT, NULL); 2412b24ab6bSSebastien Roy cv_init(&iptun->iptun_upcall_cv, NULL, CV_DRIVER, NULL); 2422b24ab6bSSebastien Roy cv_init(&iptun->iptun_enter_cv, NULL, CV_DRIVER, NULL); 2432b24ab6bSSebastien Roy 2442b24ab6bSSebastien Roy return (0); 2452b24ab6bSSebastien Roy } 2462b24ab6bSSebastien Roy 2472b24ab6bSSebastien Roy /* ARGSUSED */ 2482b24ab6bSSebastien Roy static void 2492b24ab6bSSebastien Roy iptun_destructor(void *buf, void *cdrarg) 2502b24ab6bSSebastien Roy { 2512b24ab6bSSebastien Roy iptun_t *iptun = buf; 2522b24ab6bSSebastien Roy 2532b24ab6bSSebastien Roy /* This iptun_t must not still be in use. */ 2542b24ab6bSSebastien Roy ASSERT(!(iptun->iptun_flags & (IPTUN_BOUND|IPTUN_MAC_REGISTERED| 2552b24ab6bSSebastien Roy IPTUN_MAC_STARTED|IPTUN_HASH_INSERTED|IPTUN_UPCALL_PENDING))); 2562b24ab6bSSebastien Roy 2572b24ab6bSSebastien Roy mutex_destroy(&iptun->iptun_lock); 2582b24ab6bSSebastien Roy cv_destroy(&iptun->iptun_upcall_cv); 2592b24ab6bSSebastien Roy } 260