1 /*
   2  * sppp_mod.c - modload support for PPP pseudo-device driver.
   3  *
   4  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   5  * Use is subject to license terms.
   6  *
   7  * Permission to use, copy, modify, and distribute this software and its
   8  * documentation is hereby granted, provided that the above copyright
   9  * notice appears in all copies.
  10  *
  11  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
  12  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  13  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  14  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
  15  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  16  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
  17  *
  18  * Copyright (c) 1994 The Australian National University.
  19  * All rights reserved.
  20  *
  21  * Permission to use, copy, modify, and distribute this software and its
  22  * documentation is hereby granted, provided that the above copyright
  23  * notice appears in all copies.  This software is provided without any
  24  * warranty, express or implied. The Australian National University
  25  * makes no representations about the suitability of this software for
  26  * any purpose.
  27  *
  28  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
  29  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  30  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
  31  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
  32  * OF SUCH DAMAGE.
  33  *
  34  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  36  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  37  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
  38  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
  39  * OR MODIFICATIONS.
  40  *
  41  * This driver is derived from the original SVR4 STREAMS PPP driver
  42  * originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>.
  43  *
  44  * Adi Masputra <adi.masputra@sun.com> rewrote and restructured the code
  45  * for improved performance and scalability.
  46  */
  47 
  48 #define RCSID   " $Id: sppp_mod.c,v 1.0 2000/05/08 10:53:28 masputra Exp $"
  49 
  50 #include <sys/types.h>
  51 #include <sys/systm.h>
  52 #include <sys/ddi.h>
  53 #include <sys/conf.h>
  54 #include <sys/sunddi.h>
  55 #include <sys/stat.h>
  56 #include <sys/kstat.h>
  57 #include <net/pppio.h>
  58 #include <sys/modctl.h>
  59 
  60 #include "s_common.h"
  61 #include "sppp.h"
  62 
  63 static int      _mi_driver_attach(dev_info_t *, ddi_attach_cmd_t);
  64 static int      _mi_driver_detach(dev_info_t *, ddi_detach_cmd_t);
  65 static int      _mi_driver_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  66 
  67 /*
  68  * Globals for PPP multiplexer module wrapper
  69  */
  70 extern const char sppp_module_description[];
  71 static dev_info_t *_mi_dip;
  72 
  73 #define PPP_MI_HIWAT    (PPP_MTU * 16)  /* XXX find more meaningful value */
  74 #define PPP_MI_LOWAT    (PPP_MTU * 14)  /* XXX find more meaningful value */
  75 
  76 static struct module_info sppp_modinfo = {
  77         PPP_MOD_ID,             /* mi_idnum */
  78         PPP_DRV_NAME,           /* mi_idname */
  79         0,                      /* mi_minpsz */
  80         PPP_MAXMTU,             /* mi_maxpsz */
  81         PPP_MI_HIWAT,           /* mi_hiwat */
  82         PPP_MI_LOWAT            /* mi_lowat */
  83 };
  84 
  85 static struct qinit sppp_urinit = {
  86         NULL,                   /* qi_putp */
  87         NULL,                   /* qi_srvp */
  88         sppp_open,              /* qi_qopen */
  89         sppp_close,             /* qi_qclose */
  90         NULL,                   /* qi_qadmin */
  91         &sppp_modinfo,              /* qi_minfo */
  92         NULL                    /* qi_mstat */
  93 };
  94 
  95 static struct qinit sppp_uwinit = {
  96         (int (*)())sppp_uwput,  /* qi_putp */
  97         (int (*)())sppp_uwsrv,  /* qi_srvp */
  98         NULL,                   /* qi_qopen */
  99         NULL,                   /* qi_qclose */
 100         NULL,                   /* qi_qadmin */
 101         &sppp_modinfo,              /* qi_minfo */
 102         NULL                    /* qi_mstat */
 103 };
 104 
 105 static struct qinit sppp_lrinit = {
 106         (int (*)())sppp_lrput,  /* qi_putp */
 107         (int (*)())sppp_lrsrv,  /* qi_srvp */
 108         NULL,                   /* qi_qopen */
 109         NULL,                   /* qi_qclose */
 110         NULL,                   /* qi_qadmin */
 111         &sppp_modinfo,              /* qi_minfo */
 112         NULL                    /* qi_mstat */
 113 };
 114 
 115 static struct qinit sppp_lwinit = {
 116         NULL,                   /* qi_putp */
 117         (int (*)())sppp_lwsrv,  /* qi_srvp */
 118         NULL,                   /* qi_qopen */
 119         NULL,                   /* qi_qclose */
 120         NULL,                   /* qi_qadmin */
 121         &sppp_modinfo,              /* qi_minfo */
 122         NULL                    /* qi_mstat */
 123 };
 124 
 125 static struct streamtab sppp_tab = {
 126         &sppp_urinit,               /* st_rdinit */
 127         &sppp_uwinit,               /* st_wrinit */
 128         &sppp_lrinit,               /* st_muxrinit */
 129         &sppp_lwinit                /* st_muxwrinit */
 130 };
 131 
 132 /*
 133  * Descriptions for flags values in cb_flags field:
 134  *
 135  * D_MTQPAIR:
 136  *    An inner perimeter that spans the queue pair.
 137  * D_MTOUTPERIM:
 138  *    An outer perimeter that spans over all queues in the module.
 139  * D_MTOCEXCL:
 140  *    Open & close procedures are entered exclusively at outer perimeter.
 141  * D_MTPUTSHARED:
 142  *    Entry to put procedures are done with SHARED (reader) acess
 143  *    and not EXCLUSIVE (writer) access.
 144  *
 145  * Therefore:
 146  *
 147  * 1. Open and close procedures are entered with EXCLUSIVE (writer)
 148  *    access at the inner perimeter, and with EXCLUSIVE (writer) access at
 149  *    the outer perimeter.
 150  *
 151  * 2. Put procedures are entered with SHARED (reader) access at the inner
 152  *    perimeter, and with SHARED (reader) access at the outer perimeter.
 153  *
 154  * 3. Service procedures are entered with EXCLUSIVE (writer) access at
 155  *    the inner perimeter, and with SHARED (reader) access at the
 156  *    outer perimeter.
 157  *
 158  * Do not attempt to modify these flags unless the entire corresponding
 159  * driver code is changed to accomodate the newly represented MT-STREAMS
 160  * flags. Doing so without making proper modifications to the driver code
 161  * will severely impact the intended driver behavior, and thus may affect
 162  * the system's stability and performance.
 163  */
 164 DDI_DEFINE_STREAM_OPS(sppp_ops,                                         \
 165         nulldev, nulldev,                                               \
 166         _mi_driver_attach, _mi_driver_detach, nodev, _mi_driver_info,   \
 167         D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED, \
 168         &sppp_tab, ddi_quiesce_not_supported);
 169 
 170 static struct modldrv modldrv = {
 171         &mod_driverops,                             /* drv_modops */
 172         (char *)sppp_module_description,        /* drv_linkinfo */
 173         &sppp_ops                           /* drv_dev_ops */
 174 };
 175 
 176 static struct modlinkage modlinkage = {
 177         MODREV_1,                       /* ml_rev, has to be MODREV_1 */
 178         { &modldrv, NULL }          /* ml_linkage, NULL-terminated list */
 179 };
 180 
 181 int
 182 _init(void)
 183 {
 184         return (mod_install(&modlinkage));
 185 }
 186 
 187 int
 188 _fini(void)
 189 {
 190         return (mod_remove(&modlinkage));
 191 }
 192 
 193 int
 194 _info(struct modinfo *modinfop)
 195 {
 196         return (mod_info(&modlinkage, modinfop));
 197 }
 198 
 199 /*
 200  * _mi_driver_attach()
 201  *
 202  * Description:
 203  *    Attach a point-to-point interface to the system.
 204  */
 205 static int
 206 _mi_driver_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 207 {
 208         if (cmd != DDI_ATTACH) {
 209                 return (DDI_FAILURE);
 210         }
 211         _mi_dip = dip;
 212         if (ddi_create_minor_node(dip, PPP_DRV_NAME, S_IFCHR,
 213             0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
 214                 ddi_remove_minor_node(dip, NULL);
 215                 return (DDI_FAILURE);
 216         }
 217         sppp_dlpi_pinfoinit();
 218         return (DDI_SUCCESS);
 219 }
 220 
 221 /*
 222  * _mi_driver_detach()
 223  *
 224  * Description:
 225  *    Detach an interface to the system.
 226  */
 227 static int
 228 _mi_driver_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 229 {
 230         if (cmd != DDI_DETACH) {
 231                 return (DDI_FAILURE);
 232         }
 233         ddi_remove_minor_node(dip, NULL);
 234         _mi_dip = NULL;
 235         return (DDI_SUCCESS);
 236 }
 237 
 238 /*
 239  * _mi_driver_info()
 240  *
 241  * Description:
 242  *    Translate "dev_t" to a pointer to the associated "dev_info_t".
 243  */
 244 /* ARGSUSED */
 245 static int
 246 _mi_driver_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 247     void **result)
 248 {
 249         int     rc;
 250 
 251         switch (infocmd) {
 252         case DDI_INFO_DEVT2DEVINFO:
 253                 if (_mi_dip == NULL) {
 254                         rc = DDI_FAILURE;
 255                 } else {
 256                         *result = (void *)_mi_dip;
 257                         rc = DDI_SUCCESS;
 258                 }
 259                 break;
 260         case DDI_INFO_DEVT2INSTANCE:
 261                 *result = NULL;
 262                 rc = DDI_SUCCESS;
 263                 break;
 264         default:
 265                 rc = DDI_FAILURE;
 266                 break;
 267         }
 268         return (rc);
 269 }