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.10 */ 32 33 /* 34 * Description: The pckt module packetizes messages on 35 * its read queue by pre-fixing an M_PROTO 36 * message type to certain incoming messages. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/stream.h> 42 #include <sys/stropts.h> 43 #include <sys/kmem.h> 44 #include <sys/errno.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/debug.h> 48 49 /* 50 * This is the loadable module wrapper. 51 */ 52 #include <sys/conf.h> 53 #include <sys/modctl.h> 54 55 static struct streamtab pcktinfo; 56 57 /* 58 * Per queue instances are single-threaded since the q_ptr 59 * field of queues need to be shared among threads. 60 */ 61 static struct fmodsw fsw = { 62 "pckt", 63 &pcktinfo, 64 D_NEW | D_MTPERQ | D_MP 65 }; 66 67 /* 68 * Module linkage information for the kernel. 69 */ 70 71 static struct modlstrmod modlstrmod = { 72 &mod_strmodops, 73 "pckt module", 74 &fsw 75 }; 76 77 static struct modlinkage modlinkage = { 78 MODREV_1, &modlstrmod, NULL 79 }; 80 81 82 int 83 _init(void) 84 { 85 return (mod_install(&modlinkage)); 86 } 87 88 int 89 _fini(void) 90 { 91 return (mod_remove(&modlinkage)); 92 } 93 94 int 95 _info(struct modinfo *modinfop) 96 { 97 return (mod_info(&modlinkage, modinfop)); 98 } 99 100 static int pcktopen(queue_t *, dev_t *, int, int, cred_t *); 101 static int pcktclose(queue_t *, int, cred_t *); 102 static void pcktrput(queue_t *, mblk_t *); 103 static void pcktrsrv(queue_t *); 104 static void pcktwput(queue_t *, mblk_t *); 105 static mblk_t *add_ctl_info(queue_t *, mblk_t *); 106 static void add_ctl_wkup(void *); 107 108 109 /* 110 * Stream module data structure definitions. 111 * Sits over the ptm module generally. 112 * 113 * Read side flow control strategy: Since we may be putting messages on 114 * the read q due to allocb failures, these failures must get 115 * reflected fairly quickly to the module below us. 116 * No sense in piling on messages in times of memory shortage. 117 * Further, for the case of upper level flow control, there is no 118 * compelling reason to have more buffering in this module. 119 * Thus use a hi-water mark of one. 120 * This module imposes no max packet size, there is no inherent reason 121 * in the code to do so. 122 */ 123 static struct module_info pcktiinfo = { 124 0x9898, /* module id number */ 125 "pckt", /* module name */ 126 0, /* minimum packet size */ 127 INFPSZ, /* maximum packet size */ 128 1, /* hi-water mark */ 129 0 /* lo-water mark */ 130 }; 131 132 /* 133 * Write side flow control strategy: There is no write service procedure. 134 * The write put function is pass thru, thus there is no reason to have any 135 * limits on the maximum packet size. 136 */ 137 static struct module_info pcktoinfo = { 138 0x9898, /* module id number */ 139 "pckt", /* module name */ 140 0, /* minimum packet size */ 141 INFPSZ, /* maximum packet size */ 142 0, /* hi-water mark */ 143 0 /* lo-water mark */ 144 }; 145 146 static struct qinit pcktrinit = { 147 (int (*)())pcktrput, 148 (int (*)())pcktrsrv, 149 pcktopen, 150 pcktclose, 151 NULL, 152 &pcktiinfo, 153 NULL 154 }; 155 156 static struct qinit pcktwinit = { 157 (int (*)())pcktwput, 158 NULL, 159 NULL, 160 NULL, 161 NULL, 162 &pcktoinfo, 163 NULL 164 }; 165 166 static struct streamtab pcktinfo = { 167 &pcktrinit, 168 &pcktwinit, 169 NULL, 170 NULL 171 }; 172 173 174 /* 175 * Per-instance state struct for the pckt module. 176 */ 177 struct pckt_info { 178 queue_t *pi_qptr; /* back pointer to q */ 179 bufcall_id_t pi_bufcall_id; 180 #ifdef _MULTI_DATAMODEL 181 model_t model; 182 #endif /* _MULTI_DATAMODEL */ 183 }; 184 185 /* 186 * Dummy qbufcall callback routine used by open and close. 187 * The framework will wake up qwait_sig when we return from 188 * this routine (as part of leaving the perimeters.) 189 * (The framework enters the perimeters before calling the qbufcall() callback 190 * and leaves the perimeters after the callback routine has executed. The 191 * framework performs an implicit wakeup of any thread in qwait/qwait_sig 192 * when it leaves the perimeter. See qwait(9E).) 193 */ 194 /* ARGSUSED */ 195 static void 196 dummy_callback(void *arg) 197 {} 198 199 /* 200 * pcktopen - open routine gets called when the 201 * module gets pushed onto the stream. 202 */ 203 /*ARGSUSED*/ 204 static int 205 pcktopen( 206 queue_t *q, /* pointer to the read side queue */ 207 dev_t *devp, /* pointer to stream tail's dev */ 208 int oflag, /* the user open(2) supplied flags */ 209 int sflag, /* open state flag */ 210 cred_t *credp) /* credentials */ 211 { 212 struct pckt_info *pip; 213 mblk_t *mop; /* ptr to a setopts msg block */ 214 struct stroptions *sop; 215 216 if (sflag != MODOPEN) 217 return (EINVAL); 218 219 if (q->q_ptr != NULL) { 220 /* It's already attached. */ 221 return (0); 222 } 223 224 /* 225 * Allocate state structure. 226 */ 227 pip = kmem_alloc(sizeof (*pip), KM_SLEEP); 228 bzero(pip, sizeof (*pip)); 229 230 #ifdef _MULTI_DATAMODEL 231 pip->model = ddi_model_convert_from(get_udatamodel()); 232 #endif /* _MULTI_DATAMODEL */ 233 234 /* 235 * Cross-link. 236 */ 237 pip->pi_qptr = q; 238 q->q_ptr = pip; 239 WR(q)->q_ptr = pip; 240 241 qprocson(q); 242 243 /* 244 * Initialize an M_SETOPTS message to set up hi/lo water marks on 245 * stream head read queue. 246 */ 247 248 while ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) { 249 bufcall_id_t id = qbufcall(q, sizeof (struct stroptions), 250 BPRI_MED, dummy_callback, NULL); 251 if (!qwait_sig(q)) { 252 qunbufcall(q, id); 253 kmem_free(pip, sizeof (*pip)); 254 qprocsoff(q); 255 return (EINTR); 256 } 257 qunbufcall(q, id); 258 } 259 260 261 /* 262 * XXX: Should this module really control the hi/low water marks? 263 * Is there any reason in this code to do so? 264 */ 265 mop->b_datap->db_type = M_SETOPTS; 266 mop->b_wptr += sizeof (struct stroptions); 267 sop = (struct stroptions *)mop->b_rptr; 268 sop->so_flags = SO_HIWAT | SO_LOWAT; 269 sop->so_hiwat = 512; 270 sop->so_lowat = 256; 271 272 /* 273 * Commit to the open and send the M_SETOPTS off to the stream head. 274 */ 275 putnext(q, mop); 276 277 return (0); 278 } 279 280 281 /* 282 * pcktclose - This routine gets called when the module 283 * gets popped off of the stream. 284 */ 285 286 /*ARGSUSED*/ 287 static int 288 pcktclose( 289 queue_t *q, /* Pointer to the read queue */ 290 int flag, 291 cred_t *credp) 292 { 293 struct pckt_info *pip = (struct pckt_info *)q->q_ptr; 294 295 qprocsoff(q); 296 /* 297 * Cancel outstanding qbufcall 298 */ 299 if (pip->pi_bufcall_id) { 300 qunbufcall(q, pip->pi_bufcall_id); 301 pip->pi_bufcall_id = 0; 302 } 303 /* 304 * Do not worry about msgs queued on the q, the framework 305 * will free them up. 306 */ 307 kmem_free(q->q_ptr, sizeof (struct pckt_info)); 308 q->q_ptr = WR(q)->q_ptr = NULL; 309 return (0); 310 } 311 312 /* 313 * pcktrput - Module read queue put procedure. 314 * This is called from the module or 315 * driver downstream. 316 */ 317 static void 318 pcktrput( 319 queue_t *q, /* Pointer to the read queue */ 320 mblk_t *mp) /* Pointer to the current message block */ 321 { 322 mblk_t *pckt_msgp; 323 324 325 switch (mp->b_datap->db_type) { 326 case M_FLUSH: 327 /* 328 * The PTS driver swaps the FLUSHR and FLUSHW flags 329 * we need to swap them back to reflect the actual 330 * slave side FLUSH mode. 331 */ 332 if ((*mp->b_rptr & FLUSHRW) != FLUSHRW) 333 if ((*mp->b_rptr & FLUSHRW) == FLUSHR) 334 *mp->b_rptr = FLUSHW; 335 else if ((*mp->b_rptr & FLUSHRW) == FLUSHW) 336 *mp->b_rptr = FLUSHR; 337 338 pckt_msgp = copymsg(mp); 339 if (*mp->b_rptr & FLUSHW) { 340 /* 341 * In the packet model we are not allowing 342 * flushes of the master's stream head read 343 * side queue. This is because all packet 344 * state information is stored there and 345 * a flush could destroy this data before 346 * it is read. 347 */ 348 *mp->b_rptr = FLUSHW; 349 putnext(q, mp); 350 } else { 351 /* 352 * Free messages that only flush the 353 * master's read queue. 354 */ 355 freemsg(mp); 356 } 357 358 if (pckt_msgp == NULL) 359 break; 360 361 mp = pckt_msgp; 362 /* 363 * Prefix M_PROTO and putnext. 364 */ 365 goto prefix_head; 366 367 case M_DATA: 368 case M_IOCTL: 369 case M_PROTO: 370 /* 371 * For non-priority messages, follow flow-control rules. 372 * Also, if there are messages on the q already, keep 373 * queueing them since they need to be processed in order. 374 */ 375 if (!canputnext(q) || (qsize(q) > 0)) { 376 (void) putq(q, mp); 377 break; 378 } 379 /* FALLTHROUGH */ 380 381 /* 382 * For high priority messages, skip flow control checks. 383 */ 384 case M_PCPROTO: 385 case M_READ: 386 case M_STOP: 387 case M_START: 388 case M_STARTI: 389 case M_STOPI: 390 prefix_head: 391 /* 392 * Prefix an M_PROTO header to message and pass upstream. 393 */ 394 if ((mp = add_ctl_info(q, mp)) != NULL) 395 putnext(q, mp); 396 break; 397 398 default: 399 /* 400 * For data messages, queue them back on the queue if 401 * there are messages on the queue already. This is 402 * done to preserve the order of messages. 403 * For high priority messages or for no messages on the 404 * q, simply putnext() and pass it on. 405 */ 406 if ((datamsg(mp->b_datap->db_type)) && (qsize(q) > 0)) 407 (void) putq(q, mp); 408 else 409 putnext(q, mp); 410 break; 411 } 412 } 413 414 /* 415 * pcktrsrv - module read service procedure 416 * This function deals with messages left in the queue due to 417 * (a) not enough memory to allocate the header M_PROTO message 418 * (b) flow control reasons 419 * The function will attempt to get the messages off the queue and 420 * process them. 421 */ 422 static void 423 pcktrsrv(queue_t *q) 424 { 425 mblk_t *mp; 426 427 while ((mp = getq(q)) != NULL) { 428 if (!canputnext(q)) { 429 /* 430 * For high priority messages, make sure there is no 431 * infinite loop. Disable the queue for this case. 432 * High priority messages get here only for buffer 433 * allocation failures. Thus the bufcall callout 434 * will reenable the q. 435 * XXX bug alert - nooenable will *not* prevent 436 * putbq of a hipri messages frm enabling the queue. 437 */ 438 if (!datamsg(mp->b_datap->db_type)) 439 noenable(q); 440 (void) putbq(q, mp); 441 return; 442 } 443 444 /* 445 * M_FLUSH msgs may also be here if there was a memory 446 * failure. 447 */ 448 switch (mp->b_datap->db_type) { 449 case M_FLUSH: 450 case M_PROTO: 451 case M_PCPROTO: 452 case M_STOP: 453 case M_START: 454 case M_IOCTL: 455 case M_DATA: 456 case M_READ: 457 case M_STARTI: 458 case M_STOPI: 459 /* 460 * Prefix an M_PROTO header to msg and pass upstream. 461 */ 462 if ((mp = add_ctl_info(q, mp)) == NULL) { 463 /* 464 * Running into memory or flow ctl problems. 465 */ 466 return; 467 } 468 /* FALL THROUGH */ 469 470 default: 471 putnext(q, mp); 472 break; 473 } 474 } 475 } 476 477 /* 478 * pcktwput - Module write queue put procedure. 479 * All messages are send downstream unchanged 480 */ 481 482 static void 483 pcktwput( 484 queue_t *q, /* Pointer to the read queue */ 485 mblk_t *mp) /* Pointer to current message block */ 486 { 487 putnext(q, mp); 488 } 489 490 #ifdef _MULTI_DATAMODEL 491 /* 492 * reallocb - copy the data block from the given message block into a new block. 493 * This function is used in case data block had another message block 494 * pointing to it (and hence we just copy this one data block). 495 * 496 * Returns new message block if successful. On failure it returns NULL. 497 * It also tries to do a qbufcall and if that also fails, 498 * it frees the message block. 499 */ 500 static mblk_t * 501 pckt_reallocb( 502 queue_t *q, /* Pointer to the read queue */ 503 mblk_t *mp /* Pointer to the message block to be changed */ 504 ) 505 { 506 mblk_t *nmp; 507 508 ASSERT(mp->b_datap->db_ref >= 1); 509 510 /* 511 * No reallocation is needed if there is only one reference 512 * to this data block. 513 */ 514 if (mp->b_datap->db_ref == 1) 515 return (mp); 516 517 if ((nmp = copyb(mp)) == NULL) { 518 struct pckt_info *pip = (struct pckt_info *)q->q_ptr; 519 520 noenable(q); 521 if (pip->pi_bufcall_id = qbufcall(q, mp->b_wptr - mp->b_rptr, 522 BPRI_MED, add_ctl_wkup, q)) { 523 /* 524 * Put the message back onto the q. 525 */ 526 (void) putq(q, mp); 527 } else { 528 /* 529 * Things are pretty bad and serious if bufcall fails! 530 * Drop the message in this case. 531 */ 532 freemsg(mp); 533 } 534 return ((mblk_t *)0); 535 } 536 537 nmp->b_cont = mp->b_cont; 538 freeb(mp); 539 return (nmp); 540 } 541 #endif /* _MULTI_DATAMODEL */ 542 543 /* 544 * add_ctl_info: add message control information to in coming 545 * message. 546 */ 547 static mblk_t * 548 add_ctl_info( 549 queue_t *q, /* pointer to the read queue */ 550 mblk_t *mp) /* pointer to the raw data input message */ 551 { 552 struct pckt_info *pip = (struct pckt_info *)q->q_ptr; 553 mblk_t *bp; /* pointer to the unmodified message block */ 554 555 /* 556 * Waiting on space for previous message? 557 */ 558 if (pip->pi_bufcall_id) { 559 /* 560 * Chain this message on to q for later processing. 561 */ 562 (void) putq(q, mp); 563 return (NULL); 564 } 565 566 /* 567 * Need to add the message block header as 568 * an M_PROTO type message. 569 */ 570 if ((bp = allocb(sizeof (char), BPRI_MED)) == (mblk_t *)NULL) { 571 572 /* 573 * There are two reasons to disable the q: 574 * (1) Flow control reasons should not wake up the q. 575 * (2) High priority messages will wakeup the q 576 * immediately. Disallow this. 577 */ 578 noenable(q); 579 if (pip->pi_bufcall_id = qbufcall(q, sizeof (char), BPRI_MED, 580 add_ctl_wkup, q)) { 581 /* 582 * Add the message to the q. 583 */ 584 (void) putq(q, mp); 585 } else { 586 /* 587 * Things are pretty bad and serious if bufcall fails! 588 * Drop the message in this case. 589 */ 590 freemsg(mp); 591 } 592 593 return (NULL); 594 } 595 596 /* 597 * Copy the message type information to this message. 598 */ 599 bp->b_datap->db_type = M_PROTO; 600 *(unsigned char *)bp->b_rptr = mp->b_datap->db_type; 601 bp->b_wptr++; 602 603 #ifdef _MULTI_DATAMODEL 604 /* 605 * Check the datamodel and if the calling program is 606 * an ILP32 application then we covert the M_IOCTLs and M_READs 607 * into the native ILP32 format before passing them upstream 608 * to user mode. 609 */ 610 switch (pip->model) { 611 case DDI_MODEL_ILP32: 612 switch (mp->b_datap->db_type) { 613 /* 614 * This structure must have the same shape as 615 * the * ILP32 compilation of `struct iocblk' 616 * from <sys/stream.h>. 617 */ 618 struct iocblk32 { 619 int32_t ioc_cmd; 620 caddr32_t ioc_cr; 621 uint32_t ioc_id; 622 int32_t ioc_count; 623 int32_t ioc_error; 624 int32_t ioc_rval; 625 int32_t ioc_fill1; 626 uint32_t ioc_flag; 627 int32_t ioc_filler[2]; 628 } niocblk_32; 629 struct iocblk *iocblk_64; 630 631 case M_IOCTL: 632 if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0) 633 return ((mblk_t *)0); 634 635 bzero(&niocblk_32, sizeof (niocblk_32)); 636 iocblk_64 = (struct iocblk *)mp->b_rptr; 637 638 /* Leave the pointer to cred_t structure as it is. */ 639 niocblk_32.ioc_cmd = iocblk_64->ioc_cmd; 640 niocblk_32.ioc_cr = (caddr32_t)(uintptr_t) 641 iocblk_64->ioc_cr; 642 niocblk_32.ioc_id = iocblk_64->ioc_id; 643 niocblk_32.ioc_count = iocblk_64->ioc_count; 644 niocblk_32.ioc_error = iocblk_64->ioc_error; 645 niocblk_32.ioc_rval = iocblk_64->ioc_rval; 646 niocblk_32.ioc_flag = iocblk_64->ioc_flag; 647 648 /* Copy the iocblk structure for ILP32 back */ 649 *(struct iocblk32 *)mp->b_rptr = niocblk_32; 650 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk32); 651 break; 652 653 case M_READ: 654 if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0) 655 return ((mblk_t *)0); 656 657 /* change the size_t to size32_t for ILP32 */ 658 *(size32_t *)mp->b_rptr = *(size_t *)mp->b_rptr; 659 mp->b_wptr = mp->b_rptr + sizeof (size32_t); 660 break; 661 } 662 break; 663 664 case DATAMODEL_NONE: 665 break; 666 } 667 #endif /* _MULTI_DATAMODEL */ 668 669 /* 670 * Now change the orginal message type to M_DATA and tie them up. 671 */ 672 mp->b_datap->db_type = M_DATA; 673 bp->b_cont = mp; 674 675 return (bp); 676 } 677 678 static void 679 add_ctl_wkup(void *arg) 680 { 681 queue_t *q = arg; /* ptr to the read queue */ 682 struct pckt_info *pip = (struct pckt_info *)q->q_ptr; 683 684 pip->pi_bufcall_id = 0; 685 /* 686 * Allow enabling of the q to allow the service 687 * function to do its job. 688 * 689 * Also, qenable() to schedule the q immediately. 690 * This is to ensure timely processing of high priority 691 * messages if they are on the q. 692 */ 693 enableok(q); 694 qenable(q); 695 } 696