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,                   /* ml_linkage, NULL-terminated list */
 179         NULL                            /*  of linkage structures */
 180 };
 181 
 182 int
 183 _init(void)
 184 {
 185         return (mod_install(&modlinkage));
 186 }
 187 
 188 int
 189 _fini(void)
 190 {
 191         return (mod_remove(&modlinkage));
 192 }
 193 
 194 int
 195 _info(struct modinfo *modinfop)
 196 {
 197         return (mod_info(&modlinkage, modinfop));
 198 }
 199 
 200 /*
 201  * _mi_driver_attach()
 202  *
 203  * Description:
 204  *    Attach a point-to-point interface to the system.
 205  */
 206 static int
 207 _mi_driver_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 208 {
 209         if (cmd != DDI_ATTACH) {
 210                 return (DDI_FAILURE);
 211         }
 212         _mi_dip = dip;
 213         if (ddi_create_minor_node(dip, PPP_DRV_NAME, S_IFCHR,
 214             0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
 215                 ddi_remove_minor_node(dip, NULL);
 216                 return (DDI_FAILURE);
 217         }
 218         sppp_dlpi_pinfoinit();
 219         return (DDI_SUCCESS);
 220 }
 221 
 222 /*
 223  * _mi_driver_detach()
 224  *
 225  * Description:
 226  *    Detach an interface to the system.
 227  */
 228 static int
 229 _mi_driver_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 230 {
 231         if (cmd != DDI_DETACH) {
 232                 return (DDI_FAILURE);
 233         }
 234         ddi_remove_minor_node(dip, NULL);
 235         _mi_dip = NULL;
 236         return (DDI_SUCCESS);
 237 }
 238 
 239 /*
 240  * _mi_driver_info()
 241  *
 242  * Description:
 243  *    Translate "dev_t" to a pointer to the associated "dev_info_t".
 244  */
 245 /* ARGSUSED */
 246 static int
 247 _mi_driver_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 248     void **result)
 249 {
 250         int     rc;
 251 
 252         switch (infocmd) {
 253         case DDI_INFO_DEVT2DEVINFO:
 254                 if (_mi_dip == NULL) {
 255                         rc = DDI_FAILURE;
 256                 } else {
 257                         *result = (void *)_mi_dip;
 258                         rc = DDI_SUCCESS;
 259                 }
 260                 break;
 261         case DDI_INFO_DEVT2INSTANCE:
 262                 *result = NULL;
 263                 rc = DDI_SUCCESS;
 264                 break;
 265         default:
 266                 rc = DDI_FAILURE;
 267                 break;
 268         }
 269         return (rc);
 270 }