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