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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.4 */
32
33 /*
34 * Transport Interface Library read/write module - issue 1
35 */
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stream.h>
40 #include <sys/stropts.h>
41 #include <sys/tihdr.h>
42 #include <sys/debug.h>
43 #include <sys/errno.h>
44 #include <sys/kmem.h>
45 #include <sys/tirdwr.h>
46 #include <sys/conf.h>
47 #include <sys/modctl.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
50
51 #define ORDREL 002
52 #define DISCON 004
53 #define FATAL 010
54 #define WAITACK 020
55 #define TIRDWR_ID 4
56
57 /*
58 * Per-Stream private data structure.
59 */
60 struct trw_trw {
61 queue_t *trw_rdq;
62 uint_t trw_flags;
63 };
64
65 /*
66 * stream data structure definitions
67 */
68 static int tirdwropen(queue_t *q, dev_t *dev,
69 int flag, int sflag, cred_t *cr);
70
71 static int tirdwrclose(queue_t *q, int flag, cred_t *cr);
72
73 static int check_strhead(queue_t *q);
74
75 /*
76 * To save instructions, since STREAMS ignores the return value
77 * from these functions, they are defined as void here. Kind of icky, but...
78 */
79 static void tirdwrrput(queue_t *q, mblk_t *mp);
80 static void tirdwrwput(queue_t *q, mblk_t *mp);
81
82 static struct module_info tirdwr_info = {
83 TIRDWR_ID,
84 "tirdwr",
85 0,
86 INFPSZ,
87 4096,
88 1024
89 };
90
91 static struct qinit tirdwrrinit = {
92 (int (*)())tirdwrrput,
93 (int (*)())NULL,
94 tirdwropen,
95 tirdwrclose,
96 nulldev,
97 &tirdwr_info,
98 NULL
99 };
100
101 static struct qinit tirdwrwinit = {
102 (int (*)())tirdwrwput,
103 (int (*)())NULL,
104 tirdwropen,
105 tirdwrclose,
106 nulldev,
107 &tirdwr_info,
108 NULL
109 };
110
111 static struct streamtab trwinfo = {
112 &tirdwrrinit,
113 &tirdwrwinit,
114 NULL,
115 NULL
116 };
117
118 static struct fmodsw fsw = {
119 "tirdwr",
120 &trwinfo,
121 D_NEW|D_MTQPAIR|D_MP
122 };
123
124 static struct modlstrmod modlstrmod = {
125 &mod_strmodops, "xport interface rd/wr str mod", &fsw
126 };
127
128 static struct modlinkage modlinkage = {
129 MODREV_1, &modlstrmod, NULL
130 };
131
132 int
_init(void)133 _init(void)
134 {
135 return (mod_install(&modlinkage));
136 }
137
138 int
_fini(void)139 _fini(void)
140 {
141 return (mod_remove(&modlinkage));
142 }
143
144 int
_info(struct modinfo * modinfop)145 _info(struct modinfo *modinfop)
146 {
147 return (mod_info(&modlinkage, modinfop));
148 }
149
150 static void send_fatal(queue_t *q, mblk_t *mp);
151 static void strip_strhead(queue_t *q);
152
153
154 /*
155 * tirdwropen - open routine gets called when the
156 * module gets pushed onto the stream.
157 */
158 /*ARGSUSED*/
159 static int
tirdwropen(queue_t * q,dev_t * dev,int flag,int sflag,cred_t * cr)160 tirdwropen(
161 queue_t *q,
162 dev_t *dev,
163 int flag,
164 int sflag,
165 cred_t *cr)
166 {
167 struct trw_trw *trwptr;
168
169 /* check if already open */
170 if (q->q_ptr) {
171 return (0);
172 }
173
174 /*
175 * Allocate a new trw_trw struct.
176 */
177 trwptr = kmem_alloc(sizeof (struct trw_trw), KM_SLEEP);
178
179 /* initialize data structure */
180 trwptr->trw_flags = 0;
181 trwptr->trw_rdq = q;
182 q->q_ptr = (caddr_t)trwptr;
183 WR(q)->q_ptr = (caddr_t)trwptr;
184 qprocson(q);
185
186 freezestr(q);
187
188 (void) strqset(WR(q), QMAXPSZ, 0, (uintptr_t)WR(q)->q_next->q_maxpsz);
189 (void) strqset(q, QMAXPSZ, 0, (uintptr_t)q->q_next->q_maxpsz);
190
191 if (!check_strhead(q)) {
192 unfreezestr(q);
193 qprocsoff(q);
194 kmem_free(trwptr, sizeof (struct trw_trw));
195 return (EPROTO);
196 }
197 strip_strhead(q);
198 unfreezestr(q);
199
200 return (0);
201 }
202
203 /*
204 * tirdwrclose - This routine gets called when the module
205 * gets popped off of the stream.
206 */
207
208 /*ARGSUSED1*/
209 static int
tirdwrclose(queue_t * q,int flag,cred_t * cr)210 tirdwrclose(queue_t *q, int flag, cred_t *cr)
211 {
212 struct trw_trw *trwptr;
213 mblk_t *mp;
214 union T_primitives *pptr;
215
216 qprocsoff(q);
217 trwptr = (struct trw_trw *)q->q_ptr;
218
219 ASSERT(trwptr != NULL);
220
221 /*
222 * Send up a T_DISCON_IND if necessary.
223 */
224 if ((trwptr->trw_flags & ORDREL) && !(trwptr->trw_flags & FATAL))
225 if (mp = allocb(sizeof (struct T_discon_req), BPRI_LO)) {
226 pptr = (union T_primitives *)mp->b_rptr;
227 mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_req);
228 pptr->type = T_ORDREL_REQ;
229 mp->b_datap->db_type = M_PROTO;
230 putnext(WR(q), mp);
231 }
232
233 kmem_free(trwptr, sizeof (struct trw_trw));
234
235 return (0);
236 }
237
238 /*
239 * tirdwrrput - Module read queue put procedure.
240 * This is called from the module or
241 * driver downstream.
242 */
243
244 static void
tirdwrrput(queue_t * q,mblk_t * mp)245 tirdwrrput(queue_t *q, mblk_t *mp)
246 {
247 union T_primitives *pptr;
248 struct trw_trw *trwptr;
249 mblk_t *tmp;
250
251 trwptr = (struct trw_trw *)q->q_ptr;
252
253 ASSERT(trwptr != NULL);
254
255 if ((trwptr->trw_flags & FATAL) && !(trwptr->trw_flags & WAITACK)) {
256 freemsg(mp);
257 return;
258 }
259
260 switch (mp->b_datap->db_type) {
261
262 default:
263 putnext(q, mp);
264 break;
265
266 case M_DATA:
267 putnext(q, mp);
268 break;
269
270 case M_PCPROTO:
271 case M_PROTO:
272 /* is there enough data to check type */
273 if ((mp->b_wptr - mp->b_rptr) < sizeof (t_scalar_t)) {
274 /* malformed message */
275 freemsg(mp);
276 break;
277 }
278 pptr = (union T_primitives *)mp->b_rptr;
279
280 switch (pptr->type) {
281
282 case T_EXDATA_IND:
283 send_fatal(q, mp);
284 break;
285 case T_DATA_IND:
286 if (msgdsize(mp) == 0) {
287 freemsg(mp);
288 break;
289 }
290
291 tmp = (mblk_t *)unlinkb(mp);
292 freemsg(mp);
293 putnext(q, tmp);
294 break;
295
296 case T_ORDREL_IND:
297 trwptr->trw_flags |= ORDREL;
298 mp->b_datap->db_type = M_DATA;
299 mp->b_wptr = mp->b_rptr;
300 putnext(q, mp);
301 break;
302
303 case T_DISCON_IND:
304 trwptr->trw_flags |= DISCON;
305 trwptr->trw_flags &= ~ORDREL;
306 if (msgdsize(mp) != 0) {
307 tmp = (mblk_t *)unlinkb(mp);
308 putnext(q, tmp);
309 }
310 mp->b_datap->db_type = M_HANGUP;
311 mp->b_wptr = mp->b_rptr;
312 putnext(q, mp);
313 break;
314
315 default:
316 send_fatal(q, mp);
317 break;
318 }
319 }
320 }
321
322
323 /*
324 * tirdwrwput - Module write queue put procedure.
325 * This is called from the module or
326 * stream head upstream.
327 */
328 static void
tirdwrwput(queue_t * q,mblk_t * mp)329 tirdwrwput(queue_t *q, mblk_t *mp)
330 {
331 struct trw_trw *trwptr;
332
333 trwptr = (struct trw_trw *)q->q_ptr;
334
335 ASSERT(trwptr != NULL);
336
337 if (trwptr->trw_flags & FATAL) {
338 freemsg(mp);
339 return;
340 }
341
342 switch (mp->b_datap->db_type) {
343 default:
344 putnext(q, mp);
345 break;
346
347 case M_DATA:
348 putnext(q, mp);
349 break;
350
351 case M_PROTO:
352 case M_PCPROTO:
353 send_fatal(q, mp);
354 break;
355 }
356 }
357
358
359 static void
send_fatal(queue_t * q,mblk_t * mp)360 send_fatal(queue_t *q, mblk_t *mp)
361 {
362 struct trw_trw *trwptr;
363
364 trwptr = (struct trw_trw *)q->q_ptr;
365
366 trwptr->trw_flags |= FATAL;
367 mp->b_datap->db_type = M_ERROR;
368 *mp->b_datap->db_base = EPROTO;
369 mp->b_rptr = mp->b_datap->db_base;
370 mp->b_wptr = mp->b_datap->db_base + sizeof (char);
371 freemsg(unlinkb(mp));
372 if (q->q_flag&QREADR)
373 putnext(q, mp);
374 else
375 qreply(q, mp);
376 }
377
378 static int
check_strhead(queue_t * q)379 check_strhead(queue_t *q)
380 {
381 mblk_t *mp;
382 union T_primitives *pptr;
383
384 for (mp = q->q_next->q_first; mp != NULL; mp = mp->b_next) {
385
386 switch (mp->b_datap->db_type) {
387 case M_PROTO:
388 pptr = (union T_primitives *)mp->b_rptr;
389 if ((mp->b_wptr - mp->b_rptr) < sizeof (t_scalar_t))
390 return (0);
391 switch (pptr->type) {
392
393 case T_EXDATA_IND:
394 return (0);
395 case T_DATA_IND:
396 if (mp->b_cont &&
397 (mp->b_cont->b_datap->db_type != M_DATA))
398 return (0);
399 break;
400 default:
401 return (0);
402 }
403 break;
404
405 case M_PCPROTO:
406 return (0);
407
408 case M_DATA:
409 case M_SIG:
410 break;
411 default:
412 return (0);
413 }
414 }
415 return (1);
416 }
417
418 static void
strip_strhead(queue_t * q)419 strip_strhead(queue_t *q)
420 {
421 mblk_t *mp;
422 mblk_t *emp;
423 mblk_t *tmp;
424 union T_primitives *pptr;
425
426 q = q->q_next;
427 /*CSTYLED*/
428 for (mp = q->q_first; mp != NULL; ) {
429
430 switch (mp->b_datap->db_type) {
431 case M_PROTO:
432 pptr = (union T_primitives *)mp->b_rptr;
433 switch (pptr->type) {
434
435 case T_DATA_IND:
436 if (msgdsize(mp) == 0) {
437 strip0:
438 tmp = mp->b_next;
439 rmvq(q, mp);
440 freemsg(mp);
441 mp = tmp;
442 break;
443 }
444 emp = mp->b_next;
445 rmvq(q, mp);
446 tmp = (mblk_t *)unlinkb(mp);
447 freeb(mp);
448 (void) insq(q, emp, tmp);
449 mp = emp;
450 break;
451 }
452 break;
453
454 case M_DATA:
455 if (msgdsize(mp) == 0)
456 goto strip0;
457 mp = mp->b_next;
458 break;
459
460 case M_SIG:
461 mp = mp->b_next;
462 break;
463 }
464 }
465 }
466