xref: /illumos-gate/usr/src/uts/common/io/ptem.c (revision 8c69cc8fbe729fa7b091e901c4b50508ccc6bb33)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*
32  * Description:
33  *
34  * The PTEM streams module is used as a pseudo driver emulator.  Its purpose
35  * is to emulate the ioctl() functions of a terminal device driver.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/stream.h>
41 #include <sys/stropts.h>
42 #include <sys/strsun.h>
43 #include <sys/termio.h>
44 #include <sys/pcb.h>
45 #include <sys/signal.h>
46 #include <sys/cred.h>
47 #include <sys/strtty.h>
48 #include <sys/errno.h>
49 #include <sys/cmn_err.h>
50 #include <sys/jioctl.h>
51 #include <sys/ptem.h>
52 #include <sys/ptms.h>
53 #include <sys/debug.h>
54 #include <sys/kmem.h>
55 #include <sys/ddi.h>
56 #include <sys/sunddi.h>
57 #include <sys/conf.h>
58 #include <sys/modctl.h>
59 
60 extern struct streamtab pteminfo;
61 
62 static struct fmodsw fsw = {
63 	"ptem",
64 	&pteminfo,
65 	D_MTQPAIR | D_MP
66 };
67 
68 static struct modlstrmod modlstrmod = {
69 	&mod_strmodops, "pty hardware emulator", &fsw
70 };
71 
72 static struct modlinkage modlinkage = {
73 	MODREV_1, &modlstrmod, NULL
74 };
75 
76 int
77 _init()
78 {
79 	return (mod_install(&modlinkage));
80 }
81 
82 int
83 _fini()
84 {
85 	return (mod_remove(&modlinkage));
86 }
87 
88 int
89 _info(struct modinfo *modinfop)
90 {
91 	return (mod_info(&modlinkage, modinfop));
92 }
93 
94 /*
95  * stream data structure definitions
96  */
97 static int ptemopen(queue_t *, dev_t  *, int, int, cred_t *);
98 static int ptemclose(queue_t *, int, cred_t *);
99 static void ptemrput(queue_t *, mblk_t *);
100 static void ptemwput(queue_t *, mblk_t *);
101 static void ptemwsrv(queue_t *);
102 
103 static struct module_info ptem_info = {
104 	0xabcd,
105 	"ptem",
106 	0,
107 	_TTY_BUFSIZ,
108 	_TTY_BUFSIZ,
109 	128
110 };
111 
112 static struct qinit ptemrinit = {
113 	(int (*)()) ptemrput,
114 	NULL,
115 	ptemopen,
116 	ptemclose,
117 	NULL,
118 	&ptem_info,
119 	NULL
120 };
121 
122 static struct qinit ptemwinit = {
123 	(int (*)()) ptemwput,
124 	(int (*)()) ptemwsrv,
125 	ptemopen,
126 	ptemclose,
127 	nulldev,
128 	&ptem_info,
129 	NULL
130 };
131 
132 struct streamtab pteminfo = {
133 	&ptemrinit,
134 	&ptemwinit,
135 	NULL,
136 	NULL
137 };
138 
139 static void	ptioc(queue_t *, mblk_t *, int);
140 static int	ptemwmsg(queue_t *, mblk_t *);
141 
142 /*
143  * ptemopen - open routine gets called when the module gets pushed onto the
144  * stream.
145  */
146 /* ARGSUSED */
147 static int
148 ptemopen(
149 	queue_t    *q,		/* pointer to the read side queue */
150 	dev_t   *devp,		/* pointer to stream tail's dev */
151 	int	oflag,		/* the user open(2) supplied flags */
152 	int	sflag,		/* open state flag */
153 	cred_t *credp)		/* credentials */
154 {
155 	struct ptem *ntp;	/* ptem entry for this PTEM module */
156 	mblk_t *mop;		/* an setopts mblk */
157 	struct stroptions *sop;
158 	struct termios *termiosp;
159 	int len;
160 
161 	if (sflag != MODOPEN)
162 		return (EINVAL);
163 
164 	if (q->q_ptr != NULL) {
165 		/* It's already attached. */
166 		return (0);
167 	}
168 
169 	/*
170 	 * Allocate state structure.
171 	 */
172 	ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);
173 
174 	/*
175 	 * Allocate a message block, used to pass the zero length message for
176 	 * "stty 0".
177 	 *
178 	 * NOTE: it's better to find out if such a message block can be
179 	 *	 allocated before it's needed than to not be able to
180 	 *	 deliver (for possible lack of buffers) when a hang-up
181 	 *	 occurs.
182 	 */
183 	if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
184 		kmem_free(ntp, sizeof (*ntp));
185 		return (EAGAIN);
186 	}
187 
188 	/*
189 	 * Initialize an M_SETOPTS message to set up hi/lo water marks on
190 	 * stream head read queue and add controlling tty if not set.
191 	 */
192 	mop = allocb(sizeof (struct stroptions), BPRI_MED);
193 	if (mop == NULL) {
194 		freemsg(ntp->dack_ptr);
195 		kmem_free(ntp, sizeof (*ntp));
196 		return (EAGAIN);
197 	}
198 	mop->b_datap->db_type = M_SETOPTS;
199 	mop->b_wptr += sizeof (struct stroptions);
200 	sop = (struct stroptions *)mop->b_rptr;
201 	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
202 	sop->so_hiwat = _TTY_BUFSIZ;
203 	sop->so_lowat = 256;
204 
205 	/*
206 	 * Cross-link.
207 	 */
208 	ntp->q_ptr = q;
209 	q->q_ptr = ntp;
210 	WR(q)->q_ptr = ntp;
211 
212 	/*
213 	 * Get termios defaults.  These are stored as
214 	 * a property in the "options" node.
215 	 */
216 	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
217 	    (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
218 	    len == sizeof (struct termios)) {
219 
220 		ntp->cflags = termiosp->c_cflag;
221 		kmem_free(termiosp, len);
222 	} else {
223 		/*
224 		 * Gack!  Whine about it.
225 		 */
226 		cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
227 	}
228 	ntp->wsz.ws_row = 0;
229 	ntp->wsz.ws_col = 0;
230 	ntp->wsz.ws_xpixel = 0;
231 	ntp->wsz.ws_ypixel = 0;
232 
233 	ntp->state = 0;
234 
235 	/*
236 	 * Commit to the open and send the M_SETOPTS off to the stream head.
237 	 */
238 	qprocson(q);
239 	putnext(q, mop);
240 
241 	return (0);
242 }
243 
244 
245 /*
246  * ptemclose - This routine gets called when the module gets popped off of the
247  * stream.
248  */
249 /* ARGSUSED */
250 static int
251 ptemclose(queue_t *q, int flag, cred_t *credp)
252 {
253 	struct ptem *ntp;	/* ptem entry for this PTEM module */
254 
255 	qprocsoff(q);
256 	ntp = (struct ptem *)q->q_ptr;
257 	freemsg(ntp->dack_ptr);
258 	kmem_free(ntp, sizeof (*ntp));
259 	q->q_ptr = WR(q)->q_ptr = NULL;
260 	return (0);
261 }
262 
263 
264 /*
265  * ptemrput - Module read queue put procedure.
266  *
267  * This is called from the module or driver downstream.
268  */
269 static void
270 ptemrput(queue_t *q, mblk_t *mp)
271 {
272 	struct iocblk *iocp;	/* M_IOCTL data */
273 	struct copyresp *resp;	/* transparent ioctl response struct */
274 	int error;
275 
276 	switch (mp->b_datap->db_type) {
277 	case M_DELAY:
278 	case M_READ:
279 		freemsg(mp);
280 		break;
281 
282 	case M_IOCTL:
283 		iocp = (struct iocblk *)mp->b_rptr;
284 
285 		switch (iocp->ioc_cmd) {
286 		case TCSBRK:
287 			/*
288 			 * Send a break message upstream.
289 			 *
290 			 * XXX:	Shouldn't the argument come into play in
291 			 *	determining whether or not so send an M_BREAK?
292 			 *	It certainly does in the write-side direction.
293 			 */
294 			error = miocpullup(mp, sizeof (int));
295 			if (error != 0) {
296 				miocnak(q, mp, 0, error);
297 				break;
298 			}
299 			if (!(*(int *)mp->b_cont->b_rptr)) {
300 				if (!putnextctl(q, M_BREAK)) {
301 					/*
302 					 * Send an NAK reply back
303 					 */
304 					miocnak(q, mp, 0, EAGAIN);
305 					break;
306 				}
307 			}
308 			/*
309 			 * ACK it.
310 			 */
311 			mioc2ack(mp, NULL, 0, 0);
312 			qreply(q, mp);
313 			break;
314 
315 		case JWINSIZE:
316 		case TIOCGWINSZ:
317 		case TIOCSWINSZ:
318 			ptioc(q, mp, RDSIDE);
319 			break;
320 
321 		case TIOCSIGNAL:
322 			/*
323 			 * The following subtle logic is due to the fact that
324 			 * `mp' may be in any one of three distinct formats:
325 			 *
326 			 *	1. A transparent M_IOCTL with an intptr_t-sized
327 			 *	   payload containing the signal number.
328 			 *
329 			 *	2. An I_STR M_IOCTL with an int-sized payload
330 			 *	   containing the signal number.
331 			 *
332 			 *	3. An M_IOCDATA with an int-sized payload
333 			 *	   containing the signal number.
334 			 */
335 			if (iocp->ioc_count == TRANSPARENT) {
336 				intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;
337 
338 				if (sig < 1 || sig >= NSIG) {
339 					/*
340 					 * it's transparent with pointer
341 					 * to the arg
342 					 */
343 					mcopyin(mp, NULL, sizeof (int), NULL);
344 					qreply(q, mp);
345 					break;
346 				}
347 			}
348 			ptioc(q, mp, RDSIDE);
349 			break;
350 
351 		case TIOCREMOTE:
352 			if (iocp->ioc_count != TRANSPARENT)
353 				ptioc(q, mp, RDSIDE);
354 			else {
355 				mcopyin(mp, NULL, sizeof (int), NULL);
356 				qreply(q, mp);
357 			}
358 			break;
359 
360 		default:
361 			putnext(q, mp);
362 			break;
363 		}
364 		break;
365 
366 	case M_IOCDATA:
367 		resp = (struct copyresp *)mp->b_rptr;
368 		if (resp->cp_rval) {
369 			/*
370 			 * Just free message on failure.
371 			 */
372 			freemsg(mp);
373 			break;
374 		}
375 
376 		/*
377 		 * Only need to copy data for the SET case.
378 		 */
379 		switch (resp->cp_cmd) {
380 
381 		case TIOCSWINSZ:
382 		case TIOCSIGNAL:
383 		case TIOCREMOTE:
384 			ptioc(q, mp, RDSIDE);
385 			break;
386 
387 		case JWINSIZE:
388 		case TIOCGWINSZ:
389 			mp->b_datap->db_type = M_IOCACK;
390 			mioc2ack(mp, NULL, 0, 0);
391 			qreply(q, mp);
392 			break;
393 
394 		default:
395 			freemsg(mp);
396 			break;
397 	}
398 	break;
399 
400 	case M_IOCACK:
401 	case M_IOCNAK:
402 		/*
403 		 * We only pass write-side ioctls through to the master that
404 		 * we've already ACKed or NAKed to the stream head.  Thus, we
405 		 * discard ones arriving from below, since they're redundant
406 		 * from the point of view of modules above us.
407 		 */
408 		freemsg(mp);
409 		break;
410 
411 	case M_HANGUP:
412 		/*
413 		 * clear blocked state.
414 		 */
415 		{
416 			struct ptem *ntp = (struct ptem *)q->q_ptr;
417 			if (ntp->state & OFLOW_CTL) {
418 				ntp->state &= ~OFLOW_CTL;
419 				qenable(WR(q));
420 			}
421 		}
422 	default:
423 		putnext(q, mp);
424 		break;
425 	}
426 }
427 
428 
429 /*
430  * ptemwput - Module write queue put procedure.
431  *
432  * This is called from the module or stream head upstream.
433  *
434  * XXX:	This routine is quite lazy about handling allocation failures,
435  *	basically just giving up and reporting failure.  It really ought to
436  *	set up bufcalls and only fail when it's absolutely necessary.
437  */
438 static void
439 ptemwput(queue_t *q, mblk_t *mp)
440 {
441 	struct ptem *ntp = (struct ptem *)q->q_ptr;
442 	struct iocblk *iocp;	/* outgoing ioctl structure */
443 	struct copyresp *resp;
444 	unsigned char type = mp->b_datap->db_type;
445 
446 	if (type >= QPCTL) {
447 		switch (type) {
448 
449 		case M_IOCDATA:
450 			resp = (struct copyresp *)mp->b_rptr;
451 			if (resp->cp_rval) {
452 				/*
453 				 * Just free message on failure.
454 				 */
455 				freemsg(mp);
456 				break;
457 			}
458 
459 			/*
460 			 * Only need to copy data for the SET case.
461 			 */
462 			switch (resp->cp_cmd) {
463 
464 				case TIOCSWINSZ:
465 					ptioc(q, mp, WRSIDE);
466 					break;
467 
468 				case JWINSIZE:
469 				case TIOCGWINSZ:
470 					mioc2ack(mp, NULL, 0, 0);
471 					qreply(q, mp);
472 					break;
473 
474 				default:
475 					freemsg(mp);
476 			}
477 			break;
478 
479 		case M_FLUSH:
480 			if (*mp->b_rptr & FLUSHW) {
481 				if ((ntp->state & IS_PTSTTY) &&
482 				    (*mp->b_rptr & FLUSHBAND))
483 					flushband(q, *(mp->b_rptr + 1),
484 					    FLUSHDATA);
485 				else
486 					flushq(q, FLUSHDATA);
487 			}
488 			putnext(q, mp);
489 			break;
490 
491 		case M_READ:
492 			freemsg(mp);
493 			break;
494 
495 		case M_STOP:
496 			/*
497 			 * Set the output flow control state.
498 			 */
499 			ntp->state |= OFLOW_CTL;
500 			putnext(q, mp);
501 			break;
502 
503 		case M_START:
504 			/*
505 			 * Relieve the output flow control state.
506 			 */
507 			ntp->state &= ~OFLOW_CTL;
508 			putnext(q, mp);
509 			qenable(q);
510 			break;
511 		default:
512 			putnext(q, mp);
513 			break;
514 		}
515 		return;
516 	}
517 	/*
518 	 * If our queue is nonempty or flow control persists
519 	 * downstream or module in stopped state, queue this message.
520 	 */
521 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
522 		/*
523 		 * Exception: ioctls, except for those defined to
524 		 * take effect after output has drained, should be
525 		 * processed immediately.
526 		 */
527 		switch (type) {
528 
529 		case M_IOCTL:
530 			iocp = (struct iocblk *)mp->b_rptr;
531 			switch (iocp->ioc_cmd) {
532 			/*
533 			 * Queue these.
534 			 */
535 			case TCSETSW:
536 			case TCSETSF:
537 			case TCSETAW:
538 			case TCSETAF:
539 			case TCSBRK:
540 				break;
541 
542 			/*
543 			 * Handle all others immediately.
544 			 */
545 			default:
546 				(void) ptemwmsg(q, mp);
547 				return;
548 			}
549 			break;
550 
551 		case M_DELAY: /* tty delays not supported */
552 			freemsg(mp);
553 			return;
554 
555 		case M_DATA:
556 			if ((mp->b_wptr - mp->b_rptr) < 0) {
557 				/*
558 				 * Free all bad length messages.
559 				 */
560 				freemsg(mp);
561 				return;
562 			} else if ((mp->b_wptr - mp->b_rptr) == 0) {
563 				if (!(ntp->state & IS_PTSTTY)) {
564 					freemsg(mp);
565 					return;
566 				}
567 			}
568 		}
569 		(void) putq(q, mp);
570 		return;
571 	}
572 	/*
573 	 * fast path into ptemwmsg to dispose of mp.
574 	 */
575 	if (!ptemwmsg(q, mp))
576 		(void) putq(q, mp);
577 }
578 
579 /*
580  * ptem write queue service procedure.
581  */
582 static void
583 ptemwsrv(queue_t *q)
584 {
585 	mblk_t *mp;
586 
587 	while ((mp = getq(q)) != NULL) {
588 		if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
589 			(void) putbq(q, mp);
590 			break;
591 		}
592 	}
593 }
594 
595 
596 /*
597  * This routine is called from both ptemwput and ptemwsrv to do the
598  * actual work of dealing with mp.  ptmewput will have already
599  * dealt with high priority messages.
600  *
601  * Return 1 if the message was processed completely and 0 if not.
602  */
603 static int
604 ptemwmsg(queue_t *q, mblk_t *mp)
605 {
606 	struct ptem *ntp = (struct ptem *)q->q_ptr;
607 	struct iocblk *iocp;	/* outgoing ioctl structure */
608 	struct termio *termiop;
609 	struct termios *termiosp;
610 	mblk_t *dack_ptr;		/* disconnect message ACK block */
611 	mblk_t *pckt_msgp;		/* message sent to the PCKT module */
612 	mblk_t *dp;			/* ioctl reply data */
613 	tcflag_t cflags;
614 	int error;
615 
616 	switch (mp->b_datap->db_type) {
617 
618 	case M_IOCTL:
619 		/*
620 		 * Note:  for each "set" type operation a copy
621 		 * of the M_IOCTL message is made and passed
622 		 * downstream.  Eventually the PCKT module, if
623 		 * it has been pushed, should pick up this message.
624 		 * If the PCKT module has not been pushed the master
625 		 * side stream head will free it.
626 		 */
627 		iocp = (struct iocblk *)mp->b_rptr;
628 		switch (iocp->ioc_cmd) {
629 
630 		case TCSETAF:
631 		case TCSETSF:
632 			/*
633 			 * Flush the read queue.
634 			 */
635 			if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
636 				miocnak(q, mp, 0, EAGAIN);
637 				break;
638 			}
639 			/* FALLTHROUGH */
640 
641 		case TCSETA:
642 		case TCSETAW:
643 		case TCSETS:
644 		case TCSETSW:
645 
646 			switch (iocp->ioc_cmd) {
647 			case TCSETAF:
648 			case TCSETA:
649 			case TCSETAW:
650 				error = miocpullup(mp, sizeof (struct termio));
651 				if (error != 0) {
652 					miocnak(q, mp, 0, error);
653 					goto out;
654 				}
655 				cflags = ((struct termio *)
656 				    mp->b_cont->b_rptr)->c_cflag;
657 				ntp->cflags =
658 				    (ntp->cflags & 0xffff0000 | cflags);
659 				break;
660 
661 			case TCSETSF:
662 			case TCSETS:
663 			case TCSETSW:
664 				error = miocpullup(mp, sizeof (struct termios));
665 				if (error != 0) {
666 					miocnak(q, mp, 0, error);
667 					goto out;
668 				}
669 				cflags = ((struct termios *)
670 				    mp->b_cont->b_rptr)->c_cflag;
671 				ntp->cflags = cflags;
672 				break;
673 			}
674 
675 			if ((cflags & CBAUD) == B0) {
676 				/*
677 				 * Hang-up: Send a zero length message.
678 				 */
679 				dack_ptr = ntp->dack_ptr;
680 
681 				if (dack_ptr) {
682 					ntp->dack_ptr = NULL;
683 					/*
684 					 * Send a zero length message
685 					 * downstream.
686 					 */
687 					putnext(q, dack_ptr);
688 				}
689 			} else {
690 				/*
691 				 * Make a copy of this message and pass it on
692 				 * to the PCKT module.
693 				 */
694 				if ((pckt_msgp = copymsg(mp)) == NULL) {
695 					miocnak(q, mp, 0, EAGAIN);
696 					break;
697 				}
698 				putnext(q, pckt_msgp);
699 			}
700 			/*
701 			 * Send ACK upstream.
702 			 */
703 			mioc2ack(mp, NULL, 0, 0);
704 			qreply(q, mp);
705 out:
706 			break;
707 
708 		case TCGETA:
709 			dp = allocb(sizeof (struct termio), BPRI_MED);
710 			if (dp == NULL) {
711 				miocnak(q, mp, 0, EAGAIN);
712 				break;
713 			}
714 			termiop = (struct termio *)dp->b_rptr;
715 			termiop->c_cflag = (ushort_t)ntp->cflags;
716 			mioc2ack(mp, dp, sizeof (struct termio), 0);
717 			qreply(q, mp);
718 			break;
719 
720 		case TCGETS:
721 			dp = allocb(sizeof (struct termios), BPRI_MED);
722 			if (dp == NULL) {
723 				miocnak(q, mp, 0, EAGAIN);
724 				break;
725 			}
726 			termiosp = (struct termios *)dp->b_rptr;
727 			termiosp->c_cflag = ntp->cflags;
728 			mioc2ack(mp, dp, sizeof (struct termios), 0);
729 			qreply(q, mp);
730 			break;
731 
732 		case TCSBRK:
733 			error = miocpullup(mp, sizeof (int));
734 			if (error != 0) {
735 				miocnak(q, mp, 0, error);
736 				break;
737 			}
738 
739 			/*
740 			 * Need a copy of this message to pass it on to
741 			 * the PCKT module.
742 			 */
743 			if ((pckt_msgp = copymsg(mp)) == NULL) {
744 				miocnak(q, mp, 0, EAGAIN);
745 				break;
746 			}
747 			/*
748 			 * Send a copy of the M_IOCTL to the PCKT module.
749 			 */
750 			putnext(q, pckt_msgp);
751 
752 			/*
753 			 * TCSBRK meaningful if data part of message is 0
754 			 * cf. termio(7).
755 			 */
756 			if (!(*(int *)mp->b_cont->b_rptr))
757 				(void) putnextctl(q, M_BREAK);
758 			/*
759 			 * ACK the ioctl.
760 			 */
761 			mioc2ack(mp, NULL, 0, 0);
762 			qreply(q, mp);
763 			break;
764 
765 		case JWINSIZE:
766 		case TIOCGWINSZ:
767 		case TIOCSWINSZ:
768 			ptioc(q, mp, WRSIDE);
769 			break;
770 
771 		case TIOCSTI:
772 			/*
773 			 * Simulate typing of a character at the terminal.  In
774 			 * all cases, we acknowledge the ioctl and pass a copy
775 			 * of it along for the PCKT module to encapsulate.  If
776 			 * not in remote mode, we also process the ioctl
777 			 * itself, looping the character given as its argument
778 			 * back around to the read side.
779 			 */
780 
781 			/*
782 			 * Need a copy of this message to pass on to the PCKT
783 			 * module.
784 			 */
785 			if ((pckt_msgp = copymsg(mp)) == NULL) {
786 				miocnak(q, mp, 0, EAGAIN);
787 				break;
788 			}
789 			if ((ntp->state & REMOTEMODE) == 0) {
790 				mblk_t *bp;
791 
792 				error = miocpullup(mp, sizeof (char));
793 				if (error != 0) {
794 					freemsg(pckt_msgp);
795 					miocnak(q, mp, 0, error);
796 					break;
797 				}
798 
799 				/*
800 				 * The permission checking has already been
801 				 * done at the stream head, since it has to be
802 				 * done in the context of the process doing
803 				 * the call.
804 				 */
805 				if ((bp = allocb(1, BPRI_MED)) == NULL) {
806 					freemsg(pckt_msgp);
807 					miocnak(q, mp, 0, EAGAIN);
808 					break;
809 				}
810 				/*
811 				 * XXX:	Is EAGAIN really the right response to
812 				 *	flow control blockage?
813 				 */
814 				if (!bcanputnext(RD(q), mp->b_band)) {
815 					freemsg(bp);
816 					freemsg(pckt_msgp);
817 					miocnak(q, mp, 0, EAGAIN);
818 					break;
819 				}
820 				*bp->b_wptr++ = *mp->b_cont->b_rptr;
821 				qreply(q, bp);
822 			}
823 
824 			putnext(q, pckt_msgp);
825 			mioc2ack(mp, NULL, 0, 0);
826 			qreply(q, mp);
827 			break;
828 
829 		case PTSSTTY:
830 			if (ntp->state & IS_PTSTTY) {
831 				miocnak(q, mp, 0, EEXIST);
832 			} else {
833 				ntp->state |= IS_PTSTTY;
834 				mioc2ack(mp, NULL, 0, 0);
835 				qreply(q, mp);
836 			}
837 			break;
838 
839 		default:
840 			/*
841 			 * End of the line.  The slave driver doesn't see any
842 			 * ioctls that we don't explicitly pass along to it.
843 			 */
844 			miocnak(q, mp, 0, EINVAL);
845 			break;
846 		}
847 		break;
848 
849 	case M_DELAY: /* tty delays not supported */
850 		freemsg(mp);
851 		break;
852 
853 	case M_DATA:
854 		if ((mp->b_wptr - mp->b_rptr) < 0) {
855 			/*
856 			 * Free all bad length messages.
857 			 */
858 			freemsg(mp);
859 			break;
860 		} else if ((mp->b_wptr - mp->b_rptr) == 0) {
861 			if (!(ntp->state & IS_PTSTTY)) {
862 				freemsg(mp);
863 				break;
864 			}
865 		}
866 		if (ntp->state & OFLOW_CTL)
867 			return (0);
868 
869 	default:
870 		putnext(q, mp);
871 		break;
872 
873 	}
874 
875 	return (1);
876 }
877 
878 /*
879  * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
880  */
881 static void
882 ptioc(queue_t *q, mblk_t *mp, int qside)
883 {
884 	struct ptem *tp;
885 	struct iocblk *iocp;
886 	struct winsize *wb;
887 	struct jwinsize *jwb;
888 	mblk_t *tmp;
889 	mblk_t *pckt_msgp;	/* message sent to the PCKT module */
890 	int error;
891 
892 	iocp = (struct iocblk *)mp->b_rptr;
893 	tp = (struct ptem *)q->q_ptr;
894 
895 	switch (iocp->ioc_cmd) {
896 
897 	case JWINSIZE:
898 		/*
899 		 * For compatibility:  If all zeros, NAK the message for dumb
900 		 * terminals.
901 		 */
902 		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
903 		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
904 			miocnak(q, mp, 0, EINVAL);
905 			return;
906 		}
907 
908 		tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
909 		if (tmp == NULL) {
910 			miocnak(q, mp, 0, EAGAIN);
911 			return;
912 		}
913 
914 		if (iocp->ioc_count == TRANSPARENT)
915 			mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
916 		else
917 			mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
918 
919 		jwb = (struct jwinsize *)mp->b_cont->b_rptr;
920 		jwb->bytesx = tp->wsz.ws_col;
921 		jwb->bytesy = tp->wsz.ws_row;
922 		jwb->bitsx = tp->wsz.ws_xpixel;
923 		jwb->bitsy = tp->wsz.ws_ypixel;
924 
925 		qreply(q, mp);
926 		return;
927 
928 	case TIOCGWINSZ:
929 		/*
930 		 * If all zeros NAK the message for dumb terminals.
931 		 */
932 		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
933 		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
934 			miocnak(q, mp, 0, EINVAL);
935 			return;
936 		}
937 
938 		tmp = allocb(sizeof (struct winsize), BPRI_MED);
939 		if (tmp == NULL) {
940 			miocnak(q, mp, 0, EAGAIN);
941 			return;
942 		}
943 
944 		mioc2ack(mp, tmp, sizeof (struct winsize), 0);
945 
946 		wb = (struct winsize *)mp->b_cont->b_rptr;
947 		wb->ws_row = tp->wsz.ws_row;
948 		wb->ws_col = tp->wsz.ws_col;
949 		wb->ws_xpixel = tp->wsz.ws_xpixel;
950 		wb->ws_ypixel = tp->wsz.ws_ypixel;
951 
952 		qreply(q, mp);
953 		return;
954 
955 	case TIOCSWINSZ:
956 		error = miocpullup(mp, sizeof (struct winsize));
957 		if (error != 0) {
958 			miocnak(q, mp, 0, error);
959 			return;
960 		}
961 
962 		wb = (struct winsize *)mp->b_cont->b_rptr;
963 		/*
964 		 * Send a SIGWINCH signal if the row/col information has
965 		 * changed.
966 		 */
967 		if ((tp->wsz.ws_row != wb->ws_row) ||
968 		    (tp->wsz.ws_col != wb->ws_col) ||
969 		    (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
970 		    (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
971 			/*
972 			 * SIGWINCH is always sent upstream.
973 			 */
974 			if (qside == WRSIDE)
975 				(void) putnextctl1(RD(q), M_SIG, SIGWINCH);
976 			else if (qside == RDSIDE)
977 				(void) putnextctl1(q, M_SIG, SIGWINCH);
978 			/*
979 			 * Message may have come in as an M_IOCDATA; pass it
980 			 * to the master side as an M_IOCTL.
981 			 */
982 			mp->b_datap->db_type = M_IOCTL;
983 			if (qside == WRSIDE) {
984 				/*
985 				 * Need a copy of this message to pass on to
986 				 * the PCKT module, only if the M_IOCTL
987 				 * orginated from the slave side.
988 				 */
989 				if ((pckt_msgp = copymsg(mp)) == NULL) {
990 					miocnak(q, mp, 0, EAGAIN);
991 					return;
992 				}
993 				putnext(q, pckt_msgp);
994 			}
995 			tp->wsz.ws_row = wb->ws_row;
996 			tp->wsz.ws_col = wb->ws_col;
997 			tp->wsz.ws_xpixel = wb->ws_xpixel;
998 			tp->wsz.ws_ypixel = wb->ws_ypixel;
999 		}
1000 
1001 		mioc2ack(mp, NULL, 0, 0);
1002 		qreply(q, mp);
1003 		return;
1004 
1005 	case TIOCSIGNAL: {
1006 		/*
1007 		 * This ioctl can emanate from the master side in remote
1008 		 * mode only.
1009 		 */
1010 		int	sig;
1011 
1012 		if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1013 			error = miocpullup(mp, sizeof (int));
1014 			if (error != 0) {
1015 				miocnak(q, mp, 0, error);
1016 				return;
1017 			}
1018 		}
1019 
1020 		if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1021 			sig = *(int *)mp->b_cont->b_rptr;
1022 		else
1023 			sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1024 
1025 		if (sig < 1 || sig >= NSIG) {
1026 			miocnak(q, mp, 0, EINVAL);
1027 			return;
1028 		}
1029 
1030 		/*
1031 		 * Send an M_PCSIG message up the slave's read side and
1032 		 * respond back to the master with an ACK or NAK as
1033 		 * appropriate.
1034 		 */
1035 		if (putnextctl1(q, M_PCSIG, sig) == 0) {
1036 			miocnak(q, mp, 0, EAGAIN);
1037 			return;
1038 		}
1039 
1040 		mioc2ack(mp, NULL, 0, 0);
1041 		qreply(q, mp);
1042 		return;
1043 	}
1044 
1045 	case TIOCREMOTE: {
1046 		int	onoff;
1047 		mblk_t	*mctlp;
1048 
1049 		if (DB_TYPE(mp) == M_IOCTL) {
1050 			error = miocpullup(mp, sizeof (int));
1051 			if (error != 0) {
1052 				miocnak(q, mp, 0, error);
1053 				return;
1054 			}
1055 		}
1056 
1057 		onoff = *(int *)mp->b_cont->b_rptr;
1058 
1059 		/*
1060 		 * Send M_CTL up using the iocblk format.
1061 		 */
1062 		mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1063 		if (mctlp == NULL) {
1064 			miocnak(q, mp, 0, EAGAIN);
1065 			return;
1066 		}
1067 		mctlp->b_datap->db_type = M_CTL;
1068 		putnext(q, mctlp);
1069 
1070 		/*
1071 		 * ACK the ioctl.
1072 		 */
1073 		mioc2ack(mp, NULL, 0, 0);
1074 		qreply(q, mp);
1075 
1076 		/*
1077 		 * Record state change.
1078 		 */
1079 		if (onoff)
1080 			tp->state |= REMOTEMODE;
1081 		else
1082 			tp->state &= ~REMOTEMODE;
1083 		return;
1084 	}
1085 
1086 	default:
1087 		putnext(q, mp);
1088 		return;
1089 	}
1090 }
1091