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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 30 */ 31 32 /* 33 * Pseudo Terminal Slave Driver. 34 * 35 * The pseudo-tty subsystem simulates a terminal connection, where the master 36 * side represents the terminal and the slave represents the user process's 37 * special device end point. The master device is set up as a cloned device 38 * where its major device number is the major for the clone device and its minor 39 * device number is the major for the ptm driver. There are no nodes in the file 40 * system for master devices. The master pseudo driver is opened using the 41 * open(2) system call with /dev/ptmx as the device parameter. The clone open 42 * finds the next available minor device for the ptm major device. 43 * 44 * A master device is available only if it and its corresponding slave device 45 * are not already open. When the master device is opened, the corresponding 46 * slave device is automatically locked out. Only one open is allowed on a 47 * master device. Multiple opens are allowed on the slave device. After both 48 * the master and slave have been opened, the user has two file descriptors 49 * which are the end points of a full duplex connection composed of two streams 50 * which are automatically connected at the master and slave drivers. The user 51 * may then push modules onto either side of the stream pair. 52 * 53 * The master and slave drivers pass all messages to their adjacent queues. 54 * Only the M_FLUSH needs some processing. Because the read queue of one side 55 * is connected to the write queue of the other, the FLUSHR flag is changed to 56 * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP 57 * message is sent to the slave device which will render the device 58 * unusable. The process on the slave side gets the EIO when attempting to write 59 * on that stream but it will be able to read any data remaining on the stream 60 * head read queue. When all the data has been read, read() returns 0 61 * indicating that the stream can no longer be used. On the last close of the 62 * slave device, a 0-length message is sent to the master device. When the 63 * application on the master side issues a read() or getmsg() and 0 is returned, 64 * the user of the master device decides whether to issue a close() that 65 * dismantles the pseudo-terminal subsystem. If the master device is not closed, 66 * the pseudo-tty subsystem will be available to another user to open the slave 67 * device. 68 * 69 * Synchronization: 70 * 71 * All global data synchronization between ptm/pts is done via global 72 * ptms_lock mutex which is initialized at system boot time from 73 * ptms_initspace (called from space.c). 74 * 75 * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and 76 * pt_nullmsg) are protected by pt_ttys.pt_lock mutex. 77 * 78 * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks 79 * which allow reader locks to be reacquired by the same thread (usual 80 * reader/writer locks can't be used for that purpose since it is illegal for 81 * a thread to acquire a lock it already holds, even as a reader). The sole 82 * purpose of these macros is to guarantee that the peer queue will not 83 * disappear (due to closing peer) while it is used. It is safe to use 84 * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since 85 * they are not real locks but reference counts). 86 * 87 * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave 88 * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should 89 * be set to appropriate queues *after* qprocson() is called during open (to 90 * prevent peer from accessing the queue with incomplete plumbing) and set to 91 * NULL before qprocsoff() is called during close. 92 * 93 * The pt_nullmsg field is only used in open/close routines and it is also 94 * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex 95 * holds. 96 * 97 * Lock Ordering: 98 * 99 * If both ptms_lock and per-pty lock should be held, ptms_lock should always 100 * be entered first, followed by per-pty lock. 101 * 102 * See ptms.h, ptm.c and ptms_conf.c fore more information. 103 * 104 */ 105 106 #include <sys/types.h> 107 #include <sys/param.h> 108 #include <sys/sysmacros.h> 109 #include <sys/stream.h> 110 #include <sys/stropts.h> 111 #include <sys/strsubr.h> 112 #include <sys/stat.h> 113 #include <sys/errno.h> 114 #include <sys/debug.h> 115 #include <sys/cmn_err.h> 116 #include <sys/ptms.h> 117 #include <sys/systm.h> 118 #include <sys/modctl.h> 119 #include <sys/conf.h> 120 #include <sys/ddi.h> 121 #include <sys/sunddi.h> 122 #include <sys/cred.h> 123 #include <sys/zone.h> 124 125 #ifdef DEBUG 126 int pts_debug = 0; 127 #define DBG(a) if (pts_debug) cmn_err(CE_NOTE, a) 128 #else 129 #define DBG(a) 130 #endif 131 132 static int ptsopen(queue_t *, dev_t *, int, int, cred_t *); 133 static int ptsclose(queue_t *, int, cred_t *); 134 static int ptswput(queue_t *, mblk_t *); 135 static int ptsrsrv(queue_t *); 136 static int ptswsrv(queue_t *); 137 138 /* 139 * Slave Stream Pseudo Terminal Module: stream data structure definitions 140 */ 141 static struct module_info pts_info = { 142 0xface, 143 "pts", 144 0, 145 _TTY_BUFSIZ, 146 _TTY_BUFSIZ, 147 128 148 }; 149 150 static struct qinit ptsrint = { 151 NULL, 152 ptsrsrv, 153 ptsopen, 154 ptsclose, 155 NULL, 156 &pts_info, 157 NULL 158 }; 159 160 static struct qinit ptswint = { 161 ptswput, 162 ptswsrv, 163 NULL, 164 NULL, 165 NULL, 166 &pts_info, 167 NULL 168 }; 169 170 static struct streamtab ptsinfo = { 171 &ptsrint, 172 &ptswint, 173 NULL, 174 NULL 175 }; 176 177 static int pts_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 178 static int pts_attach(dev_info_t *, ddi_attach_cmd_t); 179 static int pts_detach(dev_info_t *, ddi_detach_cmd_t); 180 181 #define PTS_CONF_FLAG (D_NEW | D_MP) 182 183 /* 184 * this will define (struct cb_ops cb_pts_ops) and (struct dev_ops pts_ops) 185 */ 186 DDI_DEFINE_STREAM_OPS(pts_ops, nulldev, nulldev, \ 187 pts_attach, pts_detach, nodev, \ 188 pts_devinfo, PTS_CONF_FLAG, &ptsinfo, ddi_quiesce_not_supported); 189 190 /* 191 * Module linkage information for the kernel. 192 */ 193 194 static struct modldrv modldrv = { 195 &mod_driverops, /* Type of module. This one is a pseudo driver */ 196 "Slave Stream Pseudo Terminal driver 'pts'", 197 &pts_ops, /* driver ops */ 198 }; 199 200 static struct modlinkage modlinkage = { 201 MODREV_1, 202 &modldrv, 203 NULL 204 }; 205 206 int 207 _init(void) 208 { 209 int rc; 210 211 if ((rc = mod_install(&modlinkage)) == 0) 212 ptms_init(); 213 return (rc); 214 } 215 216 217 int 218 _fini(void) 219 { 220 return (mod_remove(&modlinkage)); 221 } 222 223 int 224 _info(struct modinfo *modinfop) 225 { 226 return (mod_info(&modlinkage, modinfop)); 227 } 228 229 static int 230 pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 231 { 232 if (cmd != DDI_ATTACH) 233 return (DDI_FAILURE); 234 235 mutex_enter(&ptms_lock); 236 pts_dip = devi; 237 mutex_exit(&ptms_lock); 238 239 return (DDI_SUCCESS); 240 } 241 242 /*ARGSUSED*/ 243 static int 244 pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 245 { 246 if (cmd != DDI_DETACH) 247 return (DDI_FAILURE); 248 249 /* 250 * For now, pts cannot be detached. 251 */ 252 return (DDI_FAILURE); 253 } 254 255 /*ARGSUSED*/ 256 static int 257 pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 258 void **result) 259 { 260 int error; 261 262 switch (infocmd) { 263 case DDI_INFO_DEVT2DEVINFO: 264 if (pts_dip == NULL) { 265 error = DDI_FAILURE; 266 } else { 267 *result = (void *)pts_dip; 268 error = DDI_SUCCESS; 269 } 270 break; 271 case DDI_INFO_DEVT2INSTANCE: 272 *result = (void *)0; 273 error = DDI_SUCCESS; 274 break; 275 default: 276 error = DDI_FAILURE; 277 } 278 return (error); 279 } 280 281 /* ARGSUSED */ 282 /* 283 * Open the slave device. Reject a clone open and do not allow the 284 * driver to be pushed. If the slave/master pair is locked or if 285 * the master is not open, return EACCESS. 286 * Upon success, store the write queue pointer in private data and 287 * set the PTSOPEN bit in the pt_state field. 288 */ 289 static int 290 ptsopen( 291 queue_t *rqp, /* pointer to the read side queue */ 292 dev_t *devp, /* pointer to stream tail's dev */ 293 int oflag, /* the user open(2) supplied flags */ 294 int sflag, /* open state flag */ 295 cred_t *credp) /* credentials */ 296 { 297 struct pt_ttys *ptsp; 298 mblk_t *mp; 299 mblk_t *mop; /* ptr to a setopts message block */ 300 minor_t dminor = getminor(*devp); 301 struct stroptions *sop; 302 303 DDBG("entering ptsopen(%d)", dminor); 304 305 if (sflag != 0) { 306 return (EINVAL); 307 } 308 309 mutex_enter(&ptms_lock); 310 ptsp = ptms_minor2ptty(dminor); 311 312 if (ptsp == NULL) { 313 mutex_exit(&ptms_lock); 314 return (ENXIO); 315 } 316 mutex_enter(&ptsp->pt_lock); 317 318 /* 319 * Prevent opens from zones other than the one blessed by ptm. We 320 * can't even allow the global zone to open all pts's, as it would 321 * otherwise inproperly be able to claim pts's already opened by zones. 322 */ 323 if (ptsp->pt_zoneid != getzoneid()) { 324 mutex_exit(&ptsp->pt_lock); 325 mutex_exit(&ptms_lock); 326 return (EPERM); 327 } 328 329 /* 330 * Allow reopen of this device. 331 */ 332 if (rqp->q_ptr != NULL) { 333 ASSERT(rqp->q_ptr == ptsp); 334 ASSERT(ptsp->pts_rdq == rqp); 335 mutex_exit(&ptsp->pt_lock); 336 mutex_exit(&ptms_lock); 337 return (0); 338 } 339 340 DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp); 341 DDBG("ptsopen: state = %x\n", ptsp->pt_state); 342 343 ASSERT(ptsp->pt_minor == dminor); 344 345 if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) { 346 mutex_exit(&ptsp->pt_lock); 347 mutex_exit(&ptms_lock); 348 return (EAGAIN); 349 } 350 351 /* 352 * if already open, simply return... 353 */ 354 if (ptsp->pt_state & PTSOPEN) { 355 ASSERT(rqp->q_ptr == ptsp); 356 ASSERT(ptsp->pts_rdq == rqp); 357 mutex_exit(&ptsp->pt_lock); 358 mutex_exit(&ptms_lock); 359 return (0); 360 } 361 362 /* 363 * Allocate message block for setting stream head options. 364 */ 365 if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) { 366 mutex_exit(&ptsp->pt_lock); 367 mutex_exit(&ptms_lock); 368 return (ENOMEM); 369 } 370 371 /* 372 * Slave should send zero-length message to a master when it is 373 * closing. If memory is low at that time, master will not detect slave 374 * closes, this pty will not be deallocated. So, preallocate this 375 * zero-length message block early. 376 */ 377 if ((mp = allocb(0, BPRI_MED)) == NULL) { 378 mutex_exit(&ptsp->pt_lock); 379 mutex_exit(&ptms_lock); 380 freemsg(mop); 381 return (ENOMEM); 382 } 383 384 ptsp->pt_state |= PTSOPEN; 385 386 WR(rqp)->q_ptr = rqp->q_ptr = ptsp; 387 388 mutex_exit(&ptsp->pt_lock); 389 mutex_exit(&ptms_lock); 390 391 if (ptsp->pt_state & PTSTTY) 392 STREAM(rqp)->sd_flag |= STRXPG4TTY; 393 394 qprocson(rqp); 395 396 /* 397 * After qprocson pts driver is fully plumbed into the stream and can 398 * send/receive messages. Setting pts_rdq will allow master side to send 399 * messages to the slave. This setting can't occur before qprocson() is 400 * finished because slave is not ready to process them. 401 */ 402 PT_ENTER_WRITE(ptsp); 403 ptsp->pts_rdq = rqp; 404 ASSERT(ptsp->pt_nullmsg == NULL); 405 ptsp->pt_nullmsg = mp; 406 PT_EXIT_WRITE(ptsp); 407 408 /* 409 * set up hi/lo water marks on stream head read queue 410 * and add controlling tty if not set 411 */ 412 413 mop->b_datap->db_type = M_SETOPTS; 414 mop->b_wptr += sizeof (struct stroptions); 415 sop = (struct stroptions *)mop->b_rptr; 416 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY; 417 sop->so_hiwat = _TTY_BUFSIZ; 418 sop->so_lowat = 256; 419 putnext(rqp, mop); 420 421 return (0); 422 } 423 424 /* 425 * Find the address to private data identifying the slave's write 426 * queue. Send a 0-length msg up the slave's read queue to designate 427 * the master is closing. Uattach the master from the slave by nulling 428 * out master's write queue field in private data. 429 */ 430 /*ARGSUSED1*/ 431 static int 432 ptsclose(queue_t *rqp, int flag, cred_t *credp) 433 { 434 struct pt_ttys *ptsp; 435 queue_t *wqp; 436 mblk_t *mp; 437 mblk_t *bp; 438 439 /* 440 * q_ptr should never be NULL in the close routine and it is checked in 441 * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to 442 * behave gracefully. 443 */ 444 ASSERT(rqp->q_ptr != NULL); 445 if (rqp->q_ptr == NULL) { 446 qprocsoff(rqp); 447 return (0); 448 } 449 450 ptsp = (struct pt_ttys *)rqp->q_ptr; 451 452 /* 453 * Slave is going to close and doesn't want any new messages coming 454 * from the master side, so set pts_rdq to NULL. This should be done 455 * before call to qprocsoff() since slave can't process additional 456 * messages from the master after qprocsoff is called. 457 */ 458 PT_ENTER_WRITE(ptsp); 459 mp = ptsp->pt_nullmsg; 460 ptsp->pt_nullmsg = NULL; 461 ptsp->pts_rdq = NULL; 462 PT_EXIT_WRITE(ptsp); 463 464 /* 465 * Drain the ouput 466 */ 467 wqp = WR(rqp); 468 PT_ENTER_READ(ptsp); 469 while ((bp = getq(wqp)) != NULL) { 470 if (ptsp->ptm_rdq) { 471 putnext(ptsp->ptm_rdq, bp); 472 } else if (bp->b_datap->db_type == M_IOCTL) { 473 bp->b_datap->db_type = M_IOCNAK; 474 freemsg(bp->b_cont); 475 bp->b_cont = NULL; 476 qreply(wqp, bp); 477 } else { 478 freemsg(bp); 479 } 480 } 481 /* 482 * qenable master side write queue so that it can flush 483 * its messages as slaves's read queue is going away 484 */ 485 if (ptsp->ptm_rdq) { 486 if (mp) 487 putnext(ptsp->ptm_rdq, mp); 488 else 489 qenable(WR(ptsp->ptm_rdq)); 490 } else 491 freemsg(mp); 492 PT_EXIT_READ(ptsp); 493 494 qprocsoff(rqp); 495 496 rqp->q_ptr = NULL; 497 WR(rqp)->q_ptr = NULL; 498 499 ptms_close(ptsp, PTSOPEN | PTSTTY); 500 501 return (0); 502 } 503 504 505 /* 506 * The wput procedure will only handle flush messages. 507 * All other messages are queued and the write side 508 * service procedure sends them off to the master side. 509 */ 510 static int 511 ptswput(queue_t *qp, mblk_t *mp) 512 { 513 struct pt_ttys *ptsp; 514 struct iocblk *iocp; 515 unsigned char type = mp->b_datap->db_type; 516 517 DBG(("entering ptswput\n")); 518 ASSERT(qp->q_ptr); 519 520 ptsp = (struct pt_ttys *)qp->q_ptr; 521 PT_ENTER_READ(ptsp); 522 if (ptsp->ptm_rdq == NULL) { 523 DBG(("in write put proc but no master\n")); 524 /* 525 * NAK ioctl as slave side read queue is gone. 526 * Or else free the message. 527 */ 528 if (mp->b_datap->db_type == M_IOCTL) { 529 mp->b_datap->db_type = M_IOCNAK; 530 freemsg(mp->b_cont); 531 mp->b_cont = NULL; 532 qreply(qp, mp); 533 } else 534 freemsg(mp); 535 PT_EXIT_READ(ptsp); 536 return (0); 537 } 538 539 if (type >= QPCTL) { 540 switch (type) { 541 542 /* 543 * if write queue request, flush slave's write 544 * queue and send FLUSHR to ptm. If read queue 545 * request, send FLUSHR to ptm. 546 */ 547 case M_FLUSH: 548 DBG(("pts got flush request\n")); 549 if (*mp->b_rptr & FLUSHW) { 550 551 DBG(("got FLUSHW, flush pts write Q\n")); 552 if (*mp->b_rptr & FLUSHBAND) 553 /* 554 * if it is a FLUSHBAND, do flushband. 555 */ 556 flushband(qp, *(mp->b_rptr + 1), FLUSHDATA); 557 else 558 flushq(qp, FLUSHDATA); 559 560 *mp->b_rptr &= ~FLUSHW; 561 if ((*mp->b_rptr & FLUSHR) == 0) { 562 /* 563 * FLUSHW only. Change to FLUSHR and putnext 564 * to ptm, then we are done. 565 */ 566 *mp->b_rptr |= FLUSHR; 567 if (ptsp->ptm_rdq) 568 putnext(ptsp->ptm_rdq, mp); 569 break; 570 } else { 571 mblk_t *nmp; 572 573 /* It is a FLUSHRW. Duplicate the mblk */ 574 nmp = copyb(mp); 575 if (nmp) { 576 /* 577 * Change FLUSHW to FLUSHR before 578 * putnext to ptm. 579 */ 580 DBG(("putnext nmp(FLUSHR) to ptm\n")); 581 *nmp->b_rptr |= FLUSHR; 582 if (ptsp->ptm_rdq) 583 putnext(ptsp->ptm_rdq, nmp); 584 } 585 } 586 } 587 /* 588 * Since the packet module will toss any 589 * M_FLUSHES sent to the master's stream head 590 * read queue, we simply turn it around here. 591 */ 592 if (*mp->b_rptr & FLUSHR) { 593 ASSERT(RD(qp)->q_first == NULL); 594 DBG(("qreply(qp) turning FLUSHR around\n")); 595 qreply(qp, mp); 596 } else { 597 freemsg(mp); 598 } 599 break; 600 601 case M_READ: 602 /* Caused by ldterm - can not pass to master */ 603 freemsg(mp); 604 break; 605 606 default: 607 if (ptsp->ptm_rdq) 608 putnext(ptsp->ptm_rdq, mp); 609 break; 610 } 611 PT_EXIT_READ(ptsp); 612 return (0); 613 } 614 615 switch (type) { 616 617 case M_IOCTL: 618 /* 619 * For case PTSSTTY set the flag PTSTTY and ACK 620 * the ioctl so that the user program can push 621 * the associated modules to get tty semantics. 622 * See bugid 4025044 623 */ 624 iocp = (struct iocblk *)mp->b_rptr; 625 switch (iocp->ioc_cmd) { 626 default: 627 break; 628 629 case PTSSTTY: 630 if (ptsp->pt_state & PTSTTY) { 631 mp->b_datap->db_type = M_IOCNAK; 632 iocp->ioc_error = EEXIST; 633 } else { 634 mp->b_datap->db_type = M_IOCACK; 635 mutex_enter(&ptsp->pt_lock); 636 ptsp->pt_state |= PTSTTY; 637 mutex_exit(&ptsp->pt_lock); 638 iocp->ioc_error = 0; 639 } 640 iocp->ioc_count = 0; 641 qreply(qp, mp); 642 PT_EXIT_READ(ptsp); 643 return (0); 644 } 645 /* FALLTHROUGH */ 646 default: 647 /* 648 * send other messages to the master 649 */ 650 DBG(("put msg on slave's write queue\n")); 651 (void) putq(qp, mp); 652 break; 653 } 654 655 PT_EXIT_READ(ptsp); 656 DBG(("return from ptswput()\n")); 657 return (0); 658 } 659 660 661 /* 662 * enable the write side of the master. This triggers the 663 * master to send any messages queued on its write side to 664 * the read side of this slave. 665 */ 666 static int 667 ptsrsrv(queue_t *qp) 668 { 669 struct pt_ttys *ptsp; 670 671 DBG(("entering ptsrsrv\n")); 672 ASSERT(qp->q_ptr); 673 674 ptsp = (struct pt_ttys *)qp->q_ptr; 675 PT_ENTER_READ(ptsp); 676 if (ptsp->ptm_rdq == NULL) { 677 DBG(("in read srv proc but no master\n")); 678 PT_EXIT_READ(ptsp); 679 return (0); 680 } 681 qenable(WR(ptsp->ptm_rdq)); 682 PT_EXIT_READ(ptsp); 683 DBG(("leaving ptsrsrv\n")); 684 return (0); 685 } 686 687 /* 688 * If there are messages on this queue that can be sent to 689 * master, send them via putnext(). Else, if queued messages 690 * cannot be sent, leave them on this queue. If priority 691 * messages on this queue, send them to master no matter what. 692 */ 693 static int 694 ptswsrv(queue_t *qp) 695 { 696 struct pt_ttys *ptsp; 697 queue_t *ptm_rdq; 698 mblk_t *mp; 699 700 DBG(("entering ptswsrv\n")); 701 ASSERT(qp->q_ptr); 702 703 ptsp = (struct pt_ttys *)qp->q_ptr; 704 PT_ENTER_READ(ptsp); 705 if (ptsp->ptm_rdq == NULL) { 706 DBG(("in write srv proc but no master\n")); 707 /* 708 * Free messages on the write queue and send 709 * NAK for any M_IOCTL type messages to wakeup 710 * the user process waiting for ACK/NAK from 711 * the ioctl invocation 712 */ 713 while ((mp = getq(qp)) != NULL) { 714 if (mp->b_datap->db_type == M_IOCTL) { 715 mp->b_datap->db_type = M_IOCNAK; 716 freemsg(mp->b_cont); 717 mp->b_cont = NULL; 718 qreply(qp, mp); 719 } else 720 freemsg(mp); 721 } 722 PT_EXIT_READ(ptsp); 723 return (0); 724 } else { 725 ptm_rdq = ptsp->ptm_rdq; 726 } 727 728 /* 729 * while there are messages on this write queue... 730 */ 731 while ((mp = getq(qp)) != NULL) { 732 /* 733 * if don't have control message and cannot put 734 * msg. on master's read queue, put it back on 735 * this queue. 736 */ 737 if (mp->b_datap->db_type <= QPCTL && 738 !bcanputnext(ptm_rdq, mp->b_band)) { 739 DBG(("put msg. back on Q\n")); 740 (void) putbq(qp, mp); 741 break; 742 } 743 /* 744 * else send the message up master's stream 745 */ 746 DBG(("send message to master\n")); 747 putnext(ptm_rdq, mp); 748 } 749 DBG(("leaving ptswsrv\n")); 750 PT_EXIT_READ(ptsp); 751 return (0); 752 } 753