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