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