1 /* 2 * sppp_mod.c - modload support for PPP pseudo-device driver. 3 * 4 * Copyright 2004 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 #pragma ident "%Z%%M% %I% %E% SMI" 49 #define RCSID " $Id: sppp_mod.c,v 1.0 2000/05/08 10:53:28 masputra Exp $" 50 51 #include <sys/types.h> 52 #include <sys/debug.h> 53 #include <sys/systm.h> 54 #include <sys/ddi.h> 55 #include <sys/strlog.h> 56 #include <sys/conf.h> 57 #include <sys/sunddi.h> 58 #include <sys/ksynch.h> 59 #include <sys/stat.h> 60 #include <sys/kstat.h> 61 #include <sys/socket.h> 62 #include <net/pppio.h> 63 #include <sys/modctl.h> 64 65 #include "s_common.h" 66 #include "sppp.h" 67 68 static int _mi_driver_attach(dev_info_t *, ddi_attach_cmd_t); 69 static int _mi_driver_detach(dev_info_t *, ddi_detach_cmd_t); 70 static int _mi_driver_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 71 72 /* 73 * Globals for PPP multiplexer module wrapper 74 */ 75 extern const char sppp_module_description[]; 76 static dev_info_t *_mi_dip; 77 78 #define PPP_MI_HIWAT (PPP_MTU * 16) /* XXX find more meaningful value */ 79 #define PPP_MI_LOWAT (PPP_MTU * 14) /* XXX find more meaningful value */ 80 81 static struct module_info sppp_modinfo = { 82 PPP_MOD_ID, /* mi_idnum */ 83 PPP_DRV_NAME, /* mi_idname */ 84 0, /* mi_minpsz */ 85 PPP_MAXMTU, /* mi_maxpsz */ 86 PPP_MI_HIWAT, /* mi_hiwat */ 87 PPP_MI_LOWAT /* mi_lowat */ 88 }; 89 90 static struct qinit sppp_urinit = { 91 NULL, /* qi_putp */ 92 NULL, /* qi_srvp */ 93 sppp_open, /* qi_qopen */ 94 sppp_close, /* qi_qclose */ 95 NULL, /* qi_qadmin */ 96 &sppp_modinfo, /* qi_minfo */ 97 NULL /* qi_mstat */ 98 }; 99 100 static struct qinit sppp_uwinit = { 101 sppp_uwput, /* qi_putp */ 102 sppp_uwsrv, /* qi_srvp */ 103 NULL, /* qi_qopen */ 104 NULL, /* qi_qclose */ 105 NULL, /* qi_qadmin */ 106 &sppp_modinfo, /* qi_minfo */ 107 NULL /* qi_mstat */ 108 }; 109 110 static struct qinit sppp_lrinit = { 111 sppp_lrput, /* qi_putp */ 112 NULL, /* qi_srvp */ 113 NULL, /* qi_qopen */ 114 NULL, /* qi_qclose */ 115 NULL, /* qi_qadmin */ 116 &sppp_modinfo, /* qi_minfo */ 117 NULL /* qi_mstat */ 118 }; 119 120 static struct qinit sppp_lwinit = { 121 NULL, /* qi_putp */ 122 sppp_lwsrv, /* qi_srvp */ 123 NULL, /* qi_qopen */ 124 NULL, /* qi_qclose */ 125 NULL, /* qi_qadmin */ 126 &sppp_modinfo, /* qi_minfo */ 127 NULL /* qi_mstat */ 128 }; 129 130 static struct streamtab sppp_tab = { 131 &sppp_urinit, /* st_rdinit */ 132 &sppp_uwinit, /* st_wrinit */ 133 &sppp_lrinit, /* st_muxrinit */ 134 &sppp_lwinit /* st_muxwrinit */ 135 }; 136 137 /* 138 * Descriptions for flags values in cb_flags field: 139 * 140 * D_MTQPAIR: 141 * An inner perimeter that spans the queue pair. 142 * D_MTOUTPERIM: 143 * An outer perimeter that spans over all queues in the module. 144 * D_MTOCEXCL: 145 * Open & close procedures are entered exclusively at outer perimeter. 146 * D_MTPUTSHARED: 147 * Entry to put procedures are done with SHARED (reader) acess 148 * and not EXCLUSIVE (writer) access. 149 * 150 * Therefore: 151 * 152 * 1. Open and close procedures are entered with EXCLUSIVE (writer) 153 * access at the inner perimeter, and with EXCLUSIVE (writer) access at 154 * the outer perimeter. 155 * 156 * 2. Put procedures are entered with SHARED (reader) access at the inner 157 * perimeter, and with SHARED (reader) access at the outer perimeter. 158 * 159 * 3. Service procedures are entered with EXCLUSIVE (writer) access at 160 * the inner perimeter, and with SHARED (reader) access at the 161 * outer perimeter. 162 * 163 * Do not attempt to modify these flags unless the entire corresponding 164 * driver code is changed to accomodate the newly represented MT-STREAMS 165 * flags. Doing so without making proper modifications to the driver code 166 * will severely impact the intended driver behavior, and thus may affect 167 * the system's stability and performance. 168 */ 169 DDI_DEFINE_STREAM_OPS(sppp_ops, \ 170 nulldev, nulldev, \ 171 _mi_driver_attach, _mi_driver_detach, nodev, _mi_driver_info, \ 172 D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED, \ 173 &sppp_tab); 174 175 static struct modldrv modldrv = { 176 &mod_driverops, /* drv_modops */ 177 (char *)sppp_module_description, /* drv_linkinfo */ 178 &sppp_ops /* drv_dev_ops */ 179 }; 180 181 static struct modlinkage modlinkage = { 182 MODREV_1, /* ml_rev, has to be MODREV_1 */ 183 &modldrv, /* ml_linkage, NULL-terminated list */ 184 NULL /* of linkage structures */ 185 }; 186 187 int 188 _init(void) 189 { 190 return (mod_install(&modlinkage)); 191 } 192 193 int 194 _fini(void) 195 { 196 return (mod_remove(&modlinkage)); 197 } 198 199 int 200 _info(struct modinfo *modinfop) 201 { 202 return (mod_info(&modlinkage, modinfop)); 203 } 204 205 /* 206 * _mi_driver_attach() 207 * 208 * Description: 209 * Attach a point-to-point interface to the system. 210 */ 211 static int 212 _mi_driver_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 213 { 214 if (cmd != DDI_ATTACH) { 215 return (DDI_FAILURE); 216 } 217 if (ddi_create_minor_node(dip, PPP_DRV_NAME, S_IFCHR, 218 0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) { 219 ddi_remove_minor_node(dip, NULL); 220 return (DDI_FAILURE); 221 } 222 sppp_dlpi_pinfoinit(); 223 return (DDI_SUCCESS); 224 } 225 226 /* 227 * _mi_driver_detach() 228 * 229 * Description: 230 * Detach an interface to the system. 231 */ 232 static int 233 _mi_driver_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 234 { 235 if (cmd != DDI_DETACH) { 236 return (DDI_FAILURE); 237 } 238 ddi_remove_minor_node(dip, NULL); 239 return (DDI_SUCCESS); 240 } 241 242 /* 243 * _mi_driver_info() 244 * 245 * Description: 246 * Translate "dev_t" to a pointer to the associated "dev_info_t". 247 */ 248 /* ARGSUSED */ 249 static int 250 _mi_driver_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 251 void **result) 252 { 253 int rc; 254 255 switch (infocmd) { 256 case DDI_INFO_DEVT2DEVINFO: 257 if (_mi_dip == NULL) { 258 rc = DDI_FAILURE; 259 } else { 260 *result = (void *)_mi_dip; 261 rc = DDI_SUCCESS; 262 } 263 break; 264 case DDI_INFO_DEVT2INSTANCE: 265 *result = NULL; 266 rc = DDI_SUCCESS; 267 break; 268 default: 269 rc = DDI_FAILURE; 270 break; 271 } 272 return (rc); 273 } 274