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 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * sppptun_mod.c - modload support for PPP multiplexing tunnel driver.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/param.h>
  33 #include <sys/stat.h>
  34 #include <sys/systm.h>
  35 #include <sys/socket.h>
  36 #include <sys/stream.h>
  37 #include <sys/stropts.h>
  38 #include <sys/time.h>
  39 #include <sys/conf.h>
  40 #include <sys/kstat.h>
  41 #include <sys/sunddi.h>
  42 #include <net/sppptun.h>
  43 #include <netinet/in.h>
  44 
  45 #include "sppptun_mod.h"
  46 
  47 /*
  48  * Descriptions for flags values in cb_flags field:
  49  *
  50  * D_MTQPAIR:
  51  *    An inner perimeter that spans the queue pair.
  52  * D_MTOUTPERIM:
  53  *    An outer perimeter that spans over all queues in the module.
  54  * D_MTOCEXCL:
  55  *    Open & close procedures are entered exclusively at outer perimeter.
  56  * D_MTPUTSHARED:
  57  *    Entry to put procedures are done with SHARED (reader) acess
  58  *    and not EXCLUSIVE (writer) access.
  59  *
  60  * Therefore:
  61  *
  62  * 1. Open and close procedures are entered with EXCLUSIVE (writer)
  63  *    access at the inner perimeter, and with EXCLUSIVE (writer) access at
  64  *    the outer perimeter.
  65  *
  66  * 2. Put procedures are entered with SHARED (reader) access at the inner
  67  *    perimeter, and with SHARED (reader) access at the outer perimeter.
  68  *
  69  * 3. Service procedures are entered with EXCLUSIVE (writer) access at
  70  *    the inner perimeter, and with SHARED (reader) access at the
  71  *    outer perimeter.
  72  *
  73  * Do not attempt to modify these flags unless the entire corresponding
  74  * driver code is changed to accomodate the newly represented MT-STREAMS
  75  * flags. Doing so without making proper modifications to the driver code
  76  * will severely impact the intended driver behavior, and thus may affect
  77  * the system's stability and performance.
  78  */
  79 
  80 static int      tun_attach(dev_info_t *, ddi_attach_cmd_t);
  81 static int      tun_detach(dev_info_t *, ddi_detach_cmd_t);
  82 static int      tun_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  83 
  84 static dev_info_t *tun_dev_info;
  85 
  86 DDI_DEFINE_STREAM_OPS(sppptun_ops,                      \
  87         nulldev, nulldev,                               \
  88         tun_attach, tun_detach, nodev, tun_info,        \
  89         D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED, \
  90         &sppptun_tab, ddi_quiesce_not_supported);
  91 
  92 /*
  93  * This is the loadable module wrapper.
  94  */
  95 #include <sys/modctl.h>
  96 
  97 /*
  98  * Module linkage information for the kernel.
  99  */
 100 static struct fmodsw sppptun_fmodsw = {
 101         PPP_TUN_NAME,
 102         &sppptun_tab,
 103         D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED
 104 };
 105 
 106 static struct modldrv modldrv = {
 107         &mod_driverops,
 108         (char *)sppptun_driver_description,
 109         &sppptun_ops
 110 };
 111 
 112 static struct modlstrmod modlstrmod = {
 113         &mod_strmodops,
 114         (char *)sppptun_module_description,
 115         &sppptun_fmodsw
 116 };
 117 
 118 static struct modlinkage modlinkage = {
 119         MODREV_1,
 120         {   (void *)&modlstrmod,
 121             (void *)&modldrv,
 122             NULL }
 123 };
 124 
 125 int
 126 _init(void)
 127 {
 128         int retv;
 129 
 130         sppptun_init();
 131         if ((retv = mod_install(&modlinkage)) == 0)
 132                 sppptun_tcl_init();
 133         return (retv);
 134 }
 135 
 136 int
 137 _fini(void)
 138 {
 139         int retv;
 140 
 141         if ((retv = sppptun_tcl_fintest()) != 0)
 142                 return (retv);
 143         retv = mod_remove(&modlinkage);
 144         if (retv != 0)
 145                 return (retv);
 146         sppptun_tcl_fini();
 147         return (0);
 148 }
 149 
 150 int
 151 _info(struct modinfo *modinfop)
 152 {
 153         return (mod_info(&modlinkage, modinfop));
 154 }
 155 
 156 /*
 157  * tun_attach()
 158  *
 159  * Description:
 160  *    Attach a PPP tunnel driver to the system.
 161  */
 162 static int
 163 tun_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 164 {
 165         if (cmd != DDI_ATTACH)
 166                 return (DDI_FAILURE);
 167         if (ddi_create_minor_node(dip, PPP_TUN_NAME, S_IFCHR, 0, DDI_PSEUDO,
 168             CLONE_DEV) == DDI_FAILURE) {
 169                 ddi_remove_minor_node(dip, NULL);
 170                 return (DDI_FAILURE);
 171         }
 172         tun_dev_info = dip;
 173         return (DDI_SUCCESS);
 174 }
 175 
 176 /*
 177  * tun_detach()
 178  *
 179  * Description:
 180  *    Detach an interface to the system.
 181  */
 182 static int
 183 tun_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 184 {
 185         if (cmd != DDI_DETACH)
 186                 return (DDI_FAILURE);
 187         tun_dev_info = NULL;
 188         ddi_remove_minor_node(dip, NULL);
 189         return (DDI_SUCCESS);
 190 }
 191 
 192 /*
 193  * tun_info()
 194  *
 195  * Description:
 196  *    Translate "dev_t" to a pointer to the associated "dev_info_t".
 197  */
 198 /* ARGSUSED */
 199 static int
 200 tun_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 201         void **result)
 202 {
 203         int     rc;
 204 
 205         switch (infocmd) {
 206         case DDI_INFO_DEVT2DEVINFO:
 207                 if (tun_dev_info == NULL) {
 208                         rc = DDI_FAILURE;
 209                 } else {
 210                         *result = (void *)tun_dev_info;
 211                         rc = DDI_SUCCESS;
 212                 }
 213                 break;
 214         case DDI_INFO_DEVT2INSTANCE:
 215                 *result = NULL;
 216                 rc = DDI_SUCCESS;
 217                 break;
 218         default:
 219                 rc = DDI_FAILURE;
 220                 break;
 221         }
 222         return (rc);
 223 }