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 }