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
_init(void)183 _init(void)
184 {
185 return (mod_install(&modlinkage));
186 }
187
188 int
_fini(void)189 _fini(void)
190 {
191 return (mod_remove(&modlinkage));
192 }
193
194 int
_info(struct modinfo * modinfop)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
_mi_driver_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
_mi_driver_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
_mi_driver_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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 }
271