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