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 	sppp_uwput,		/* qi_putp */
97 	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 	sppp_lrput,		/* qi_putp */
107 	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 	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