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