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