xref: /illumos-gate/usr/src/uts/common/io/ptem.c (revision b80bb91b66c2de22d944d93cdc98304eb32be782)
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 		/* FALLTHROUGH */
423 	default:
424 		putnext(q, mp);
425 		break;
426 	}
427 }
428 
429 
430 /*
431  * ptemwput - Module write queue put procedure.
432  *
433  * This is called from the module or stream head upstream.
434  *
435  * XXX:	This routine is quite lazy about handling allocation failures,
436  *	basically just giving up and reporting failure.  It really ought to
437  *	set up bufcalls and only fail when it's absolutely necessary.
438  */
439 static void
440 ptemwput(queue_t *q, mblk_t *mp)
441 {
442 	struct ptem *ntp = (struct ptem *)q->q_ptr;
443 	struct iocblk *iocp;	/* outgoing ioctl structure */
444 	struct copyresp *resp;
445 	unsigned char type = mp->b_datap->db_type;
446 
447 	if (type >= QPCTL) {
448 		switch (type) {
449 
450 		case M_IOCDATA:
451 			resp = (struct copyresp *)mp->b_rptr;
452 			if (resp->cp_rval) {
453 				/*
454 				 * Just free message on failure.
455 				 */
456 				freemsg(mp);
457 				break;
458 			}
459 
460 			/*
461 			 * Only need to copy data for the SET case.
462 			 */
463 			switch (resp->cp_cmd) {
464 
465 				case TIOCSWINSZ:
466 					ptioc(q, mp, WRSIDE);
467 					break;
468 
469 				case JWINSIZE:
470 				case TIOCGWINSZ:
471 					mioc2ack(mp, NULL, 0, 0);
472 					qreply(q, mp);
473 					break;
474 
475 				default:
476 					freemsg(mp);
477 			}
478 			break;
479 
480 		case M_FLUSH:
481 			if (*mp->b_rptr & FLUSHW) {
482 				if ((ntp->state & IS_PTSTTY) &&
483 				    (*mp->b_rptr & FLUSHBAND))
484 					flushband(q, *(mp->b_rptr + 1),
485 					    FLUSHDATA);
486 				else
487 					flushq(q, FLUSHDATA);
488 			}
489 			putnext(q, mp);
490 			break;
491 
492 		case M_READ:
493 			freemsg(mp);
494 			break;
495 
496 		case M_STOP:
497 			/*
498 			 * Set the output flow control state.
499 			 */
500 			ntp->state |= OFLOW_CTL;
501 			putnext(q, mp);
502 			break;
503 
504 		case M_START:
505 			/*
506 			 * Relieve the output flow control state.
507 			 */
508 			ntp->state &= ~OFLOW_CTL;
509 			putnext(q, mp);
510 			qenable(q);
511 			break;
512 		default:
513 			putnext(q, mp);
514 			break;
515 		}
516 		return;
517 	}
518 	/*
519 	 * If our queue is nonempty or flow control persists
520 	 * downstream or module in stopped state, queue this message.
521 	 */
522 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
523 		/*
524 		 * Exception: ioctls, except for those defined to
525 		 * take effect after output has drained, should be
526 		 * processed immediately.
527 		 */
528 		switch (type) {
529 
530 		case M_IOCTL:
531 			iocp = (struct iocblk *)mp->b_rptr;
532 			switch (iocp->ioc_cmd) {
533 			/*
534 			 * Queue these.
535 			 */
536 			case TCSETSW:
537 			case TCSETSF:
538 			case TCSETAW:
539 			case TCSETAF:
540 			case TCSBRK:
541 				break;
542 
543 			/*
544 			 * Handle all others immediately.
545 			 */
546 			default:
547 				(void) ptemwmsg(q, mp);
548 				return;
549 			}
550 			break;
551 
552 		case M_DELAY: /* tty delays not supported */
553 			freemsg(mp);
554 			return;
555 
556 		case M_DATA:
557 			if ((mp->b_wptr - mp->b_rptr) < 0) {
558 				/*
559 				 * Free all bad length messages.
560 				 */
561 				freemsg(mp);
562 				return;
563 			} else if ((mp->b_wptr - mp->b_rptr) == 0) {
564 				if (!(ntp->state & IS_PTSTTY)) {
565 					freemsg(mp);
566 					return;
567 				}
568 			}
569 		}
570 		(void) putq(q, mp);
571 		return;
572 	}
573 	/*
574 	 * fast path into ptemwmsg to dispose of mp.
575 	 */
576 	if (!ptemwmsg(q, mp))
577 		(void) putq(q, mp);
578 }
579 
580 /*
581  * ptem write queue service procedure.
582  */
583 static void
584 ptemwsrv(queue_t *q)
585 {
586 	mblk_t *mp;
587 
588 	while ((mp = getq(q)) != NULL) {
589 		if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
590 			(void) putbq(q, mp);
591 			break;
592 		}
593 	}
594 }
595 
596 
597 /*
598  * This routine is called from both ptemwput and ptemwsrv to do the
599  * actual work of dealing with mp.  ptmewput will have already
600  * dealt with high priority messages.
601  *
602  * Return 1 if the message was processed completely and 0 if not.
603  */
604 static int
605 ptemwmsg(queue_t *q, mblk_t *mp)
606 {
607 	struct ptem *ntp = (struct ptem *)q->q_ptr;
608 	struct iocblk *iocp;	/* outgoing ioctl structure */
609 	struct termio *termiop;
610 	struct termios *termiosp;
611 	mblk_t *dack_ptr;		/* disconnect message ACK block */
612 	mblk_t *pckt_msgp;		/* message sent to the PCKT module */
613 	mblk_t *dp;			/* ioctl reply data */
614 	tcflag_t cflags;
615 	int error;
616 
617 	switch (mp->b_datap->db_type) {
618 
619 	case M_IOCTL:
620 		/*
621 		 * Note:  for each "set" type operation a copy
622 		 * of the M_IOCTL message is made and passed
623 		 * downstream.  Eventually the PCKT module, if
624 		 * it has been pushed, should pick up this message.
625 		 * If the PCKT module has not been pushed the master
626 		 * side stream head will free it.
627 		 */
628 		iocp = (struct iocblk *)mp->b_rptr;
629 		switch (iocp->ioc_cmd) {
630 
631 		case TCSETAF:
632 		case TCSETSF:
633 			/*
634 			 * Flush the read queue.
635 			 */
636 			if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
637 				miocnak(q, mp, 0, EAGAIN);
638 				break;
639 			}
640 			/* FALLTHROUGH */
641 
642 		case TCSETA:
643 		case TCSETAW:
644 		case TCSETS:
645 		case TCSETSW:
646 
647 			switch (iocp->ioc_cmd) {
648 			case TCSETAF:
649 			case TCSETA:
650 			case TCSETAW:
651 				error = miocpullup(mp, sizeof (struct termio));
652 				if (error != 0) {
653 					miocnak(q, mp, 0, error);
654 					goto out;
655 				}
656 				cflags = ((struct termio *)
657 				    mp->b_cont->b_rptr)->c_cflag;
658 				ntp->cflags =
659 				    (ntp->cflags & 0xffff0000 | cflags);
660 				break;
661 
662 			case TCSETSF:
663 			case TCSETS:
664 			case TCSETSW:
665 				error = miocpullup(mp, sizeof (struct termios));
666 				if (error != 0) {
667 					miocnak(q, mp, 0, error);
668 					goto out;
669 				}
670 				cflags = ((struct termios *)
671 				    mp->b_cont->b_rptr)->c_cflag;
672 				ntp->cflags = cflags;
673 				break;
674 			}
675 
676 			if ((cflags & CBAUD) == B0) {
677 				/*
678 				 * Hang-up: Send a zero length message.
679 				 */
680 				dack_ptr = ntp->dack_ptr;
681 
682 				if (dack_ptr) {
683 					ntp->dack_ptr = NULL;
684 					/*
685 					 * Send a zero length message
686 					 * downstream.
687 					 */
688 					putnext(q, dack_ptr);
689 				}
690 			} else {
691 				/*
692 				 * Make a copy of this message and pass it on
693 				 * to the PCKT module.
694 				 */
695 				if ((pckt_msgp = copymsg(mp)) == NULL) {
696 					miocnak(q, mp, 0, EAGAIN);
697 					break;
698 				}
699 				putnext(q, pckt_msgp);
700 			}
701 			/*
702 			 * Send ACK upstream.
703 			 */
704 			mioc2ack(mp, NULL, 0, 0);
705 			qreply(q, mp);
706 out:
707 			break;
708 
709 		case TCGETA:
710 			dp = allocb(sizeof (struct termio), BPRI_MED);
711 			if (dp == NULL) {
712 				miocnak(q, mp, 0, EAGAIN);
713 				break;
714 			}
715 			termiop = (struct termio *)dp->b_rptr;
716 			termiop->c_cflag = (ushort_t)ntp->cflags;
717 			mioc2ack(mp, dp, sizeof (struct termio), 0);
718 			qreply(q, mp);
719 			break;
720 
721 		case TCGETS:
722 			dp = allocb(sizeof (struct termios), BPRI_MED);
723 			if (dp == NULL) {
724 				miocnak(q, mp, 0, EAGAIN);
725 				break;
726 			}
727 			termiosp = (struct termios *)dp->b_rptr;
728 			termiosp->c_cflag = ntp->cflags;
729 			mioc2ack(mp, dp, sizeof (struct termios), 0);
730 			qreply(q, mp);
731 			break;
732 
733 		case TCSBRK:
734 			error = miocpullup(mp, sizeof (int));
735 			if (error != 0) {
736 				miocnak(q, mp, 0, error);
737 				break;
738 			}
739 
740 			/*
741 			 * Need a copy of this message to pass it on to
742 			 * the PCKT module.
743 			 */
744 			if ((pckt_msgp = copymsg(mp)) == NULL) {
745 				miocnak(q, mp, 0, EAGAIN);
746 				break;
747 			}
748 			/*
749 			 * Send a copy of the M_IOCTL to the PCKT module.
750 			 */
751 			putnext(q, pckt_msgp);
752 
753 			/*
754 			 * TCSBRK meaningful if data part of message is 0
755 			 * cf. termio(7).
756 			 */
757 			if (!(*(int *)mp->b_cont->b_rptr))
758 				(void) putnextctl(q, M_BREAK);
759 			/*
760 			 * ACK the ioctl.
761 			 */
762 			mioc2ack(mp, NULL, 0, 0);
763 			qreply(q, mp);
764 			break;
765 
766 		case JWINSIZE:
767 		case TIOCGWINSZ:
768 		case TIOCSWINSZ:
769 			ptioc(q, mp, WRSIDE);
770 			break;
771 
772 		case TIOCSTI:
773 			/*
774 			 * Simulate typing of a character at the terminal.  In
775 			 * all cases, we acknowledge the ioctl and pass a copy
776 			 * of it along for the PCKT module to encapsulate.  If
777 			 * not in remote mode, we also process the ioctl
778 			 * itself, looping the character given as its argument
779 			 * back around to the read side.
780 			 */
781 
782 			/*
783 			 * Need a copy of this message to pass on to the PCKT
784 			 * module.
785 			 */
786 			if ((pckt_msgp = copymsg(mp)) == NULL) {
787 				miocnak(q, mp, 0, EAGAIN);
788 				break;
789 			}
790 			if ((ntp->state & REMOTEMODE) == 0) {
791 				mblk_t *bp;
792 
793 				error = miocpullup(mp, sizeof (char));
794 				if (error != 0) {
795 					freemsg(pckt_msgp);
796 					miocnak(q, mp, 0, error);
797 					break;
798 				}
799 
800 				/*
801 				 * The permission checking has already been
802 				 * done at the stream head, since it has to be
803 				 * done in the context of the process doing
804 				 * the call.
805 				 */
806 				if ((bp = allocb(1, BPRI_MED)) == NULL) {
807 					freemsg(pckt_msgp);
808 					miocnak(q, mp, 0, EAGAIN);
809 					break;
810 				}
811 				/*
812 				 * XXX:	Is EAGAIN really the right response to
813 				 *	flow control blockage?
814 				 */
815 				if (!bcanputnext(RD(q), mp->b_band)) {
816 					freemsg(bp);
817 					freemsg(pckt_msgp);
818 					miocnak(q, mp, 0, EAGAIN);
819 					break;
820 				}
821 				*bp->b_wptr++ = *mp->b_cont->b_rptr;
822 				qreply(q, bp);
823 			}
824 
825 			putnext(q, pckt_msgp);
826 			mioc2ack(mp, NULL, 0, 0);
827 			qreply(q, mp);
828 			break;
829 
830 		case PTSSTTY:
831 			if (ntp->state & IS_PTSTTY) {
832 				miocnak(q, mp, 0, EEXIST);
833 			} else {
834 				ntp->state |= IS_PTSTTY;
835 				mioc2ack(mp, NULL, 0, 0);
836 				qreply(q, mp);
837 			}
838 			break;
839 
840 		default:
841 			/*
842 			 * End of the line.  The slave driver doesn't see any
843 			 * ioctls that we don't explicitly pass along to it.
844 			 */
845 			miocnak(q, mp, 0, EINVAL);
846 			break;
847 		}
848 		break;
849 
850 	case M_DELAY: /* tty delays not supported */
851 		freemsg(mp);
852 		break;
853 
854 	case M_DATA:
855 		if ((mp->b_wptr - mp->b_rptr) < 0) {
856 			/*
857 			 * Free all bad length messages.
858 			 */
859 			freemsg(mp);
860 			break;
861 		} else if ((mp->b_wptr - mp->b_rptr) == 0) {
862 			if (!(ntp->state & IS_PTSTTY)) {
863 				freemsg(mp);
864 				break;
865 			}
866 		}
867 		if (ntp->state & OFLOW_CTL)
868 			return (0);
869 		/* FALLTHROUGH */
870 
871 	default:
872 		putnext(q, mp);
873 		break;
874 
875 	}
876 
877 	return (1);
878 }
879 
880 /*
881  * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
882  */
883 static void
884 ptioc(queue_t *q, mblk_t *mp, int qside)
885 {
886 	struct ptem *tp;
887 	struct iocblk *iocp;
888 	struct winsize *wb;
889 	struct jwinsize *jwb;
890 	mblk_t *tmp;
891 	mblk_t *pckt_msgp;	/* message sent to the PCKT module */
892 	int error;
893 
894 	iocp = (struct iocblk *)mp->b_rptr;
895 	tp = (struct ptem *)q->q_ptr;
896 
897 	switch (iocp->ioc_cmd) {
898 
899 	case JWINSIZE:
900 		/*
901 		 * For compatibility:  If all zeros, NAK the message for dumb
902 		 * terminals.
903 		 */
904 		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
905 		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
906 			miocnak(q, mp, 0, EINVAL);
907 			return;
908 		}
909 
910 		tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
911 		if (tmp == NULL) {
912 			miocnak(q, mp, 0, EAGAIN);
913 			return;
914 		}
915 
916 		if (iocp->ioc_count == TRANSPARENT)
917 			mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
918 		else
919 			mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
920 
921 		jwb = (struct jwinsize *)mp->b_cont->b_rptr;
922 		jwb->bytesx = tp->wsz.ws_col;
923 		jwb->bytesy = tp->wsz.ws_row;
924 		jwb->bitsx = tp->wsz.ws_xpixel;
925 		jwb->bitsy = tp->wsz.ws_ypixel;
926 
927 		qreply(q, mp);
928 		return;
929 
930 	case TIOCGWINSZ:
931 		/*
932 		 * If all zeros NAK the message for dumb terminals.
933 		 */
934 		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
935 		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
936 			miocnak(q, mp, 0, EINVAL);
937 			return;
938 		}
939 
940 		tmp = allocb(sizeof (struct winsize), BPRI_MED);
941 		if (tmp == NULL) {
942 			miocnak(q, mp, 0, EAGAIN);
943 			return;
944 		}
945 
946 		mioc2ack(mp, tmp, sizeof (struct winsize), 0);
947 
948 		wb = (struct winsize *)mp->b_cont->b_rptr;
949 		wb->ws_row = tp->wsz.ws_row;
950 		wb->ws_col = tp->wsz.ws_col;
951 		wb->ws_xpixel = tp->wsz.ws_xpixel;
952 		wb->ws_ypixel = tp->wsz.ws_ypixel;
953 
954 		qreply(q, mp);
955 		return;
956 
957 	case TIOCSWINSZ:
958 		error = miocpullup(mp, sizeof (struct winsize));
959 		if (error != 0) {
960 			miocnak(q, mp, 0, error);
961 			return;
962 		}
963 
964 		wb = (struct winsize *)mp->b_cont->b_rptr;
965 		/*
966 		 * Send a SIGWINCH signal if the row/col information has
967 		 * changed.
968 		 */
969 		if ((tp->wsz.ws_row != wb->ws_row) ||
970 		    (tp->wsz.ws_col != wb->ws_col) ||
971 		    (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
972 		    (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
973 			/*
974 			 * SIGWINCH is always sent upstream.
975 			 */
976 			if (qside == WRSIDE)
977 				(void) putnextctl1(RD(q), M_SIG, SIGWINCH);
978 			else if (qside == RDSIDE)
979 				(void) putnextctl1(q, M_SIG, SIGWINCH);
980 			/*
981 			 * Message may have come in as an M_IOCDATA; pass it
982 			 * to the master side as an M_IOCTL.
983 			 */
984 			mp->b_datap->db_type = M_IOCTL;
985 			if (qside == WRSIDE) {
986 				/*
987 				 * Need a copy of this message to pass on to
988 				 * the PCKT module, only if the M_IOCTL
989 				 * orginated from the slave side.
990 				 */
991 				if ((pckt_msgp = copymsg(mp)) == NULL) {
992 					miocnak(q, mp, 0, EAGAIN);
993 					return;
994 				}
995 				putnext(q, pckt_msgp);
996 			}
997 			tp->wsz.ws_row = wb->ws_row;
998 			tp->wsz.ws_col = wb->ws_col;
999 			tp->wsz.ws_xpixel = wb->ws_xpixel;
1000 			tp->wsz.ws_ypixel = wb->ws_ypixel;
1001 		}
1002 
1003 		mioc2ack(mp, NULL, 0, 0);
1004 		qreply(q, mp);
1005 		return;
1006 
1007 	case TIOCSIGNAL: {
1008 		/*
1009 		 * This ioctl can emanate from the master side in remote
1010 		 * mode only.
1011 		 */
1012 		int	sig;
1013 
1014 		if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1015 			error = miocpullup(mp, sizeof (int));
1016 			if (error != 0) {
1017 				miocnak(q, mp, 0, error);
1018 				return;
1019 			}
1020 		}
1021 
1022 		if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1023 			sig = *(int *)mp->b_cont->b_rptr;
1024 		else
1025 			sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1026 
1027 		if (sig < 1 || sig >= NSIG) {
1028 			miocnak(q, mp, 0, EINVAL);
1029 			return;
1030 		}
1031 
1032 		/*
1033 		 * Send an M_PCSIG message up the slave's read side and
1034 		 * respond back to the master with an ACK or NAK as
1035 		 * appropriate.
1036 		 */
1037 		if (putnextctl1(q, M_PCSIG, sig) == 0) {
1038 			miocnak(q, mp, 0, EAGAIN);
1039 			return;
1040 		}
1041 
1042 		mioc2ack(mp, NULL, 0, 0);
1043 		qreply(q, mp);
1044 		return;
1045 	}
1046 
1047 	case TIOCREMOTE: {
1048 		int	onoff;
1049 		mblk_t	*mctlp;
1050 
1051 		if (DB_TYPE(mp) == M_IOCTL) {
1052 			error = miocpullup(mp, sizeof (int));
1053 			if (error != 0) {
1054 				miocnak(q, mp, 0, error);
1055 				return;
1056 			}
1057 		}
1058 
1059 		onoff = *(int *)mp->b_cont->b_rptr;
1060 
1061 		/*
1062 		 * Send M_CTL up using the iocblk format.
1063 		 */
1064 		mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1065 		if (mctlp == NULL) {
1066 			miocnak(q, mp, 0, EAGAIN);
1067 			return;
1068 		}
1069 		mctlp->b_datap->db_type = M_CTL;
1070 		putnext(q, mctlp);
1071 
1072 		/*
1073 		 * ACK the ioctl.
1074 		 */
1075 		mioc2ack(mp, NULL, 0, 0);
1076 		qreply(q, mp);
1077 
1078 		/*
1079 		 * Record state change.
1080 		 */
1081 		if (onoff)
1082 			tp->state |= REMOTEMODE;
1083 		else
1084 			tp->state &= ~REMOTEMODE;
1085 		return;
1086 	}
1087 
1088 	default:
1089 		putnext(q, mp);
1090 		return;
1091 	}
1092 }
1093