ptm.c revision 4321:a8930ec16e52
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 2007 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"
30
31/*
32 * Pseudo Terminal Master 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 * If O_NONBLOCK or O_NDELAY is set, read on the master side returns -1 with
69 * errno set to EAGAIN if no data is available, and write returns -1 with errno
70 * set to EAGAIN if there is internal flow control.
71 *
72 * IOCTLS:
73 *
74 *  ISPTM: determines whether the file descriptor is that of an open master
75 *	   device. Return code of zero indicates that the file descriptor
76 *	   represents master device.
77 *
78 *  UNLKPT: unlocks the master and slave devices.  It returns 0 on success. On
79 *	    failure, the errno is set to EINVAL indicating that the master
80 *	    device is not open.
81 *
82 *  ZONEPT: sets the zone membership of the associated pts device.
83 *
84 *  GRPPT:  sets the group owner of the associated pts device.
85 *
86 * Synchronization:
87 *
88 *   All global data synchronization between ptm/pts is done via global
89 *   ptms_lock mutex which is initialized at system boot time from
90 *   ptms_initspace (called from space.c).
91 *
92 *   Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
93 *   pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
94 *
95 *   PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
96 *   which allow reader locks to be reacquired by the same thread (usual
97 *   reader/writer locks can't be used for that purpose since it is illegal for
98 *   a thread to acquire a lock it already holds, even as a reader). The sole
99 *   purpose of these macros is to guarantee that the peer queue will not
100 *   disappear (due to closing peer) while it is used. It is safe to use
101 *   PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
102 *   they are not real locks but reference counts).
103 *
104 *   PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
105 *   open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
106 *   be set to appropriate queues *after* qprocson() is called during open (to
107 *   prevent peer from accessing the queue with incomplete plumbing) and set to
108 *   NULL before qprocsoff() is called during close.
109 *
110 *   The pt_nullmsg field is only used in open/close routines and it is also
111 *   protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
112 *   holds.
113 *
114 * Lock Ordering:
115 *
116 *   If both ptms_lock and per-pty lock should be held, ptms_lock should always
117 *   be entered first, followed by per-pty lock.
118 *
119 * See ptms.h, pts.c and ptms_conf.c for more information.
120 */
121
122#include <sys/types.h>
123#include <sys/param.h>
124#include <sys/file.h>
125#include <sys/sysmacros.h>
126#include <sys/stream.h>
127#include <sys/stropts.h>
128#include <sys/proc.h>
129#include <sys/errno.h>
130#include <sys/debug.h>
131#include <sys/cmn_err.h>
132#include <sys/ptms.h>
133#include <sys/stat.h>
134#include <sys/strsun.h>
135#include <sys/systm.h>
136#include <sys/modctl.h>
137#include <sys/conf.h>
138#include <sys/ddi.h>
139#include <sys/sunddi.h>
140#include <sys/zone.h>
141
142#ifdef DEBUG
143int ptm_debug = 0;
144#define	DBG(a)	 if (ptm_debug) cmn_err(CE_NOTE, a)
145#else
146#define	DBG(a)
147#endif
148
149static int ptmopen(queue_t *, dev_t *, int, int, cred_t *);
150static int ptmclose(queue_t *, int, cred_t *);
151static void ptmwput(queue_t *, mblk_t *);
152static void ptmrsrv(queue_t *);
153static void ptmwsrv(queue_t *);
154
155/*
156 * Master Stream Pseudo Terminal Module: stream data structure definitions
157 */
158
159static struct module_info ptm_info = {
160	0xdead,
161	"ptm",
162	0,
163	512,
164	512,
165	128
166};
167
168static struct qinit ptmrint = {
169	NULL,
170	(int (*)()) ptmrsrv,
171	ptmopen,
172	ptmclose,
173	NULL,
174	&ptm_info,
175	NULL
176};
177
178static struct qinit ptmwint = {
179	(int (*)()) ptmwput,
180	(int (*)()) ptmwsrv,
181	NULL,
182	NULL,
183	NULL,
184	&ptm_info,
185	NULL
186};
187
188static struct streamtab ptminfo = {
189	&ptmrint,
190	&ptmwint,
191	NULL,
192	NULL
193};
194
195static int ptm_attach(dev_info_t *, ddi_attach_cmd_t);
196static int ptm_detach(dev_info_t *, ddi_detach_cmd_t);
197static int ptm_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
198
199static dev_info_t	*ptm_dip;		/* private devinfo pointer */
200
201/*
202 * this will define (struct cb_ops cb_ptm_ops) and (struct dev_ops ptm_ops)
203 */
204DDI_DEFINE_STREAM_OPS(ptm_ops, nulldev, nulldev, ptm_attach, ptm_detach,
205    nodev, ptm_devinfo, D_MP, &ptminfo);
206
207/*
208 * Module linkage information for the kernel.
209 */
210
211static struct modldrv modldrv = {
212	&mod_driverops, /* Type of module.  This one is a pseudo driver */
213	"Master streams driver 'ptm' %I%",
214	&ptm_ops,	/* driver ops */
215};
216
217static struct modlinkage modlinkage = {
218	MODREV_1,
219	&modldrv,
220	NULL
221};
222
223int
224_init(void)
225{
226	int rc;
227
228	if ((rc = mod_install(&modlinkage)) == 0)
229		ptms_init();
230	return (rc);
231}
232
233int
234_fini(void)
235{
236	return (mod_remove(&modlinkage));
237}
238
239int
240_info(struct modinfo *modinfop)
241{
242	return (mod_info(&modlinkage, modinfop));
243}
244
245static int
246ptm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
247{
248	if (cmd != DDI_ATTACH)
249		return (DDI_FAILURE);
250
251	if (ddi_create_minor_node(devi, "ptmajor", S_IFCHR,
252	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
253		ddi_remove_minor_node(devi, NULL);
254		return (DDI_FAILURE);
255	}
256	if (ddi_create_minor_node(devi, "ptmx", S_IFCHR,
257	    0, DDI_PSEUDO, CLONE_DEV) == DDI_FAILURE) {
258		ddi_remove_minor_node(devi, NULL);
259		return (DDI_FAILURE);
260	}
261	ptm_dip = devi;
262
263	return (DDI_SUCCESS);
264}
265
266static int
267ptm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
268{
269	if (cmd != DDI_DETACH)
270		return (DDI_FAILURE);
271
272	ddi_remove_minor_node(devi, NULL);
273	return (DDI_SUCCESS);
274}
275
276/*ARGSUSED*/
277static int
278ptm_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
279    void **result)
280{
281	int error;
282
283	switch (infocmd) {
284	case DDI_INFO_DEVT2DEVINFO:
285		if (ptm_dip == NULL) {
286			error = DDI_FAILURE;
287		} else {
288			*result = (void *)ptm_dip;
289			error = DDI_SUCCESS;
290		}
291		break;
292	case DDI_INFO_DEVT2INSTANCE:
293		*result = (void *)0;
294		error = DDI_SUCCESS;
295		break;
296	default:
297		error = DDI_FAILURE;
298	}
299	return (error);
300}
301
302
303/* ARGSUSED */
304/*
305 * Open a minor of the master device. Store the write queue pointer and set the
306 * pt_state field to (PTMOPEN | PTLOCK).
307 * This code will work properly with both clone opens and direct opens of the
308 * master device.
309 */
310static int
311ptmopen(
312	queue_t *rqp,		/* pointer to the read side queue */
313	dev_t   *devp,		/* pointer to stream tail's dev */
314	int	oflag,		/* the user open(2) supplied flags */
315	int	sflag,		/* open state flag */
316	cred_t  *credp)		/* credentials */
317{
318	struct pt_ttys	*ptmp;
319	mblk_t		*mop;		/* ptr to a setopts message block */
320	struct stroptions *sop;
321	minor_t		dminor = getminor(*devp);
322
323	/* Allow reopen */
324	if (rqp->q_ptr != NULL)
325		return (0);
326
327	if (sflag & MODOPEN)
328		return (ENXIO);
329
330	if (!(sflag & CLONEOPEN) && dminor != 0) {
331		/*
332		 * This is a direct open to specific master device through an
333		 * artificially created entry with specific minor in
334		 * /dev/directory. Such behavior is not supported.
335		 */
336		return (ENXIO);
337	}
338
339	/*
340	 * The master open requires that the slave be attached
341	 * before it returns so that attempts to open the slave will
342	 * succeeed
343	 */
344	if (ptms_attach_slave() != 0) {
345		return (ENXIO);
346	}
347
348	mop = allocb(sizeof (struct stroptions), BPRI_MED);
349	if (mop == NULL) {
350		DDBG("ptmopen(): mop allocation failed\n", 0);
351		return (ENOMEM);
352	}
353
354	if ((ptmp = pt_ttys_alloc()) == NULL) {
355		DDBG("ptmopen(): pty allocation failed\n", 0);
356		freemsg(mop);
357		return (ENOMEM);
358	}
359
360	dminor = ptmp->pt_minor;
361
362	DDBGP("ptmopen(): allocated ptmp %p\n", (uintptr_t)ptmp);
363	DDBG("ptmopen(): allocated minor %d\n", dminor);
364
365	WR(rqp)->q_ptr = rqp->q_ptr = ptmp;
366
367	qprocson(rqp);
368
369	/* Allow slave to send messages to master */
370	PT_ENTER_WRITE(ptmp);
371	ptmp->ptm_rdq = rqp;
372	PT_EXIT_WRITE(ptmp);
373
374	/*
375	 * set up hi/lo water marks on stream head read queue
376	 * and add controlling tty if not set
377	 */
378	mop->b_datap->db_type = M_SETOPTS;
379	mop->b_wptr += sizeof (struct stroptions);
380	sop = (struct stroptions *)mop->b_rptr;
381	if (oflag & FNOCTTY)
382		sop->so_flags = SO_HIWAT | SO_LOWAT;
383	else
384		sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
385	sop->so_hiwat = 512;
386	sop->so_lowat = 256;
387	putnext(rqp, mop);
388
389	/*
390	 * The input, devp, is a major device number, the output is put
391	 * into the same parm as a major,minor pair.
392	 */
393	*devp = makedevice(getmajor(*devp), dminor);
394
395	return (0);
396}
397
398
399/*
400 * Find the address to private data identifying the slave's write queue.
401 * Send a hang-up message up the slave's read queue to designate the
402 * master/slave pair is tearing down. Uattach the master and slave by
403 * nulling out the write queue fields in the private data structure.
404 * Finally, unlock the master/slave pair and mark the master as closed.
405 */
406/*ARGSUSED1*/
407static int
408ptmclose(queue_t *rqp, int flag, cred_t *credp)
409{
410	struct pt_ttys	*ptmp;
411	queue_t *pts_rdq;
412
413	ASSERT(rqp->q_ptr);
414
415	ptmp = (struct pt_ttys *)rqp->q_ptr;
416	PT_ENTER_READ(ptmp);
417	if (ptmp->pts_rdq) {
418		pts_rdq = ptmp->pts_rdq;
419		if (pts_rdq->q_next) {
420			DBG(("send hangup message to slave\n"));
421			(void) putnextctl(pts_rdq, M_HANGUP);
422		}
423	}
424	PT_EXIT_READ(ptmp);
425	/*
426	 * ptm_rdq should be cleared before call to qprocsoff() to prevent pts
427	 * write procedure to attempt using ptm_rdq after qprocsoff.
428	 */
429	PT_ENTER_WRITE(ptmp);
430	ptmp->ptm_rdq = NULL;
431	freemsg(ptmp->pt_nullmsg);
432	ptmp->pt_nullmsg = NULL;
433	/*
434	 * qenable slave side write queue so that it can flush
435	 * its messages as master's read queue is going away
436	 */
437	if (ptmp->pts_rdq)
438		qenable(WR(ptmp->pts_rdq));
439	PT_EXIT_WRITE(ptmp);
440
441	qprocsoff(rqp);
442
443	/* Finish the close */
444	rqp->q_ptr = NULL;
445	WR(rqp)->q_ptr = NULL;
446
447	ptms_close(ptmp, PTMOPEN | PTLOCK);
448
449	return (0);
450}
451
452static boolean_t
453ptmptsopencb(ptmptsopencb_arg_t arg)
454{
455	struct pt_ttys	*ptmp = (struct pt_ttys *)arg;
456	boolean_t rval;
457
458	PT_ENTER_READ(ptmp);
459	rval = (ptmp->pt_nullmsg != NULL);
460	PT_EXIT_READ(ptmp);
461	return (rval);
462}
463
464/*
465 * The wput procedure will only handle ioctl and flush messages.
466 */
467static void
468ptmwput(queue_t *qp, mblk_t *mp)
469{
470	struct pt_ttys	*ptmp;
471	struct iocblk	*iocp;
472
473	DBG(("entering ptmwput\n"));
474	ASSERT(qp->q_ptr);
475
476	ptmp = (struct pt_ttys *)qp->q_ptr;
477	PT_ENTER_READ(ptmp);
478
479	switch (mp->b_datap->db_type) {
480	/*
481	 * if write queue request, flush master's write
482	 * queue and send FLUSHR up slave side. If read
483	 * queue request, convert to FLUSHW and putnext().
484	 */
485	case M_FLUSH:
486		{
487			unsigned char flush_flg = 0;
488
489			DBG(("ptm got flush request\n"));
490			if (*mp->b_rptr & FLUSHW) {
491				DBG(("got FLUSHW, flush ptm write Q\n"));
492				if (*mp->b_rptr & FLUSHBAND)
493					/*
494					 * if it is a FLUSHBAND, do flushband.
495					 */
496					flushband(qp, *(mp->b_rptr + 1),
497					    FLUSHDATA);
498				else
499					flushq(qp, FLUSHDATA);
500				flush_flg = (*mp->b_rptr & ~FLUSHW) | FLUSHR;
501			}
502			if (*mp->b_rptr & FLUSHR) {
503				DBG(("got FLUSHR, set FLUSHW\n"));
504				flush_flg |= (*mp->b_rptr & ~FLUSHR) | FLUSHW;
505			}
506			if (flush_flg != 0 && ptmp->pts_rdq &&
507			    !(ptmp->pt_state & PTLOCK)) {
508				DBG(("putnext to pts\n"));
509				*mp->b_rptr = flush_flg;
510				putnext(ptmp->pts_rdq, mp);
511			} else
512				freemsg(mp);
513			break;
514		}
515
516	case M_IOCTL:
517		iocp = (struct iocblk *)mp->b_rptr;
518		switch (iocp->ioc_cmd) {
519		default:
520			if ((ptmp->pt_state & PTLOCK) ||
521			    (ptmp->pts_rdq == NULL)) {
522				DBG(("got M_IOCTL but no slave\n"));
523				miocnak(qp, mp, 0, EINVAL);
524				PT_EXIT_READ(ptmp);
525				return;
526			}
527			(void) putq(qp, mp);
528			break;
529		case UNLKPT:
530			mutex_enter(&ptmp->pt_lock);
531			ptmp->pt_state &= ~PTLOCK;
532			mutex_exit(&ptmp->pt_lock);
533			/*FALLTHROUGH*/
534		case ISPTM:
535			DBG(("ack the UNLKPT/ISPTM\n"));
536			miocack(qp, mp, 0, 0);
537			break;
538		case ZONEPT:
539		{
540			zoneid_t z;
541			int error;
542
543			if ((error = drv_priv(iocp->ioc_cr)) != 0) {
544				miocnak(qp, mp, 0, error);
545				break;
546			}
547			if ((error = miocpullup(mp, sizeof (zoneid_t))) != 0) {
548				miocnak(qp, mp, 0, error);
549				break;
550			}
551			z = *((zoneid_t *)mp->b_cont->b_rptr);
552			if (z < MIN_ZONEID || z > MAX_ZONEID) {
553				miocnak(qp, mp, 0, EINVAL);
554				break;
555			}
556
557			mutex_enter(&ptmp->pt_lock);
558			ptmp->pt_zoneid = z;
559			mutex_exit(&ptmp->pt_lock);
560			miocack(qp, mp, 0, 0);
561			break;
562		}
563		case OWNERPT:
564		{
565			pt_own_t *ptop;
566			int error;
567
568			if ((error = miocpullup(mp, sizeof (pt_own_t))) != 0) {
569				miocnak(qp, mp, 0, error);
570				break;
571			}
572
573			ptop = (pt_own_t *)mp->b_cont->b_rptr;
574
575			if (!VALID_UID(ptop->pto_ruid) ||
576			    !VALID_GID(ptop->pto_rgid)) {
577				miocnak(qp, mp, 0, EINVAL);
578				break;
579			}
580
581			mutex_enter(&ptmp->pt_lock);
582			ptmp->pt_ruid = ptop->pto_ruid;
583			ptmp->pt_rgid = ptop->pto_rgid;
584			mutex_exit(&ptmp->pt_lock);
585			miocack(qp, mp, 0, 0);
586			break;
587		}
588		case PTMPTSOPENCB:
589		{
590			mblk_t		*dp;	/* ioctl reply data */
591			ptmptsopencb_t	*ppocb;
592
593			/* only allow the kernel to invoke this ioctl */
594			if (iocp->ioc_cr != kcred) {
595				miocnak(qp, mp, 0, EINVAL);
596				break;
597			}
598
599			/* we don't support transparent ioctls */
600			ASSERT(iocp->ioc_count != TRANSPARENT);
601			if (iocp->ioc_count == TRANSPARENT) {
602				miocnak(qp, mp, 0, EINVAL);
603				break;
604			}
605
606			/* allocate a response message */
607			dp = allocb(sizeof (ptmptsopencb_t), BPRI_MED);
608			if (dp == NULL) {
609				miocnak(qp, mp, 0, EAGAIN);
610				break;
611			}
612
613			/* initialize the ioctl results */
614			ppocb = (ptmptsopencb_t *)dp->b_rptr;
615			ppocb->ppocb_func = ptmptsopencb;
616			ppocb->ppocb_arg = (ptmptsopencb_arg_t)ptmp;
617
618			/* send the reply data */
619			mioc2ack(mp, dp, sizeof (ptmptsopencb_t), 0);
620			qreply(qp, mp);
621			break;
622		}
623		}
624		break;
625
626	case M_READ:
627		/* Caused by ldterm - can not pass to slave */
628		freemsg(mp);
629		break;
630
631	/*
632	 * send other messages to slave
633	 */
634	default:
635		if ((ptmp->pt_state  & PTLOCK) || (ptmp->pts_rdq == NULL)) {
636			DBG(("got msg. but no slave\n"));
637			mp = mexchange(NULL, mp, 2, M_ERROR, -1);
638			if (mp != NULL) {
639				mp->b_rptr[0] = NOERROR;
640				mp->b_rptr[1] = EINVAL;
641				qreply(qp, mp);
642			}
643			PT_EXIT_READ(ptmp);
644			return;
645		}
646		DBG(("put msg on master's write queue\n"));
647		(void) putq(qp, mp);
648		break;
649	}
650	DBG(("return from ptmwput()\n"));
651	PT_EXIT_READ(ptmp);
652}
653
654
655/*
656 * enable the write side of the slave. This triggers the
657 * slave to send any messages queued on its write side to
658 * the read side of this master.
659 */
660static void
661ptmrsrv(queue_t *qp)
662{
663	struct pt_ttys	*ptmp;
664
665	DBG(("entering ptmrsrv\n"));
666	ASSERT(qp->q_ptr);
667
668	ptmp = (struct pt_ttys *)qp->q_ptr;
669	PT_ENTER_READ(ptmp);
670	if (ptmp->pts_rdq) {
671		qenable(WR(ptmp->pts_rdq));
672	}
673	PT_EXIT_READ(ptmp);
674	DBG(("leaving ptmrsrv\n"));
675}
676
677
678/*
679 * If there are messages on this queue that can be sent to
680 * slave, send them via putnext(). Else, if queued messages
681 * cannot be sent, leave them on this queue. If priority
682 * messages on this queue, send them to slave no matter what.
683 */
684static void
685ptmwsrv(queue_t *qp)
686{
687	struct pt_ttys	*ptmp;
688	mblk_t 		*mp;
689
690	DBG(("entering ptmwsrv\n"));
691	ASSERT(qp->q_ptr);
692
693	ptmp = (struct pt_ttys *)qp->q_ptr;
694
695	if ((mp = getq(qp)) == NULL) {
696		/* If there are no messages there's nothing to do. */
697		DBG(("leaving ptmwsrv (no messages)\n"));
698		return;
699	}
700
701	PT_ENTER_READ(ptmp);
702	if ((ptmp->pt_state  & PTLOCK) || (ptmp->pts_rdq == NULL)) {
703		DBG(("in master write srv proc but no slave\n"));
704		/*
705		 * Free messages on the write queue and send
706		 * NAK for any M_IOCTL type messages to wakeup
707		 * the user process waiting for ACK/NAK from
708		 * the ioctl invocation
709		 */
710		do {
711			if (mp->b_datap->db_type == M_IOCTL)
712				miocnak(qp, mp, 0, EINVAL);
713			else
714				freemsg(mp);
715		} while ((mp = getq(qp)) != NULL);
716		flushq(qp, FLUSHALL);
717
718		mp = mexchange(NULL, NULL, 2, M_ERROR, -1);
719		if (mp != NULL) {
720			mp->b_rptr[0] = NOERROR;
721			mp->b_rptr[1] = EINVAL;
722			qreply(qp, mp);
723		}
724		PT_EXIT_READ(ptmp);
725		return;
726	}
727	/*
728	 * while there are messages on this write queue...
729	 */
730	do {
731		/*
732		 * if don't have control message and cannot put
733		 * msg. on slave's read queue, put it back on
734		 * this queue.
735		 */
736		if (mp->b_datap->db_type <= QPCTL &&
737		    !bcanputnext(ptmp->pts_rdq, mp->b_band)) {
738			DBG(("put msg. back on queue\n"));
739			(void) putbq(qp, mp);
740			break;
741		}
742		/*
743		 * else send the message up slave's stream
744		 */
745		DBG(("send message to slave\n"));
746		putnext(ptmp->pts_rdq, mp);
747	} while ((mp = getq(qp)) != NULL);
748	DBG(("leaving ptmwsrv\n"));
749	PT_EXIT_READ(ptmp);
750}
751