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 133 _init(void) 134 { 135 return (mod_install(&modlinkage)); 136 } 137 138 int 139 _fini(void) 140 { 141 return (mod_remove(&modlinkage)); 142 } 143 144 int 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 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 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 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 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 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 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 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 }