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
63static int	_mi_driver_attach(dev_info_t *, ddi_attach_cmd_t);
64static int	_mi_driver_detach(dev_info_t *, ddi_detach_cmd_t);
65static int	_mi_driver_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
66
67/*
68 * Globals for PPP multiplexer module wrapper
69 */
70extern const char sppp_module_description[];
71static 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
76static 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
85static 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
95static 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
105static 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
115static 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
125static 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 */
164DDI_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
170static struct modldrv modldrv = {
171	&mod_driverops,				/* drv_modops */
172	(char *)sppp_module_description,	/* drv_linkinfo */
173	&sppp_ops				/* drv_dev_ops */
174};
175
176static 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
182int
183_init(void)
184{
185	return (mod_install(&modlinkage));
186}
187
188int
189_fini(void)
190{
191	return (mod_remove(&modlinkage));
192}
193
194int
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 */
206static 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 */
228static 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 */
246static 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}
271