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 #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.13 */
32
33 /*
34 * Description:
35 *
36 * The PTEM streams module is used as a pseudo driver emulator. Its purpose
37 * is to emulate the ioctl() functions of a terminal device driver.
38 */
39
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/stream.h>
43 #include <sys/stropts.h>
44 #include <sys/strsun.h>
45 #include <sys/termio.h>
46 #include <sys/pcb.h>
47 #include <sys/signal.h>
48 #include <sys/cred.h>
49 #include <sys/strtty.h>
50 #include <sys/errno.h>
51 #include <sys/cmn_err.h>
52 #include <sys/jioctl.h>
53 #include <sys/ptem.h>
54 #include <sys/ptms.h>
55 #include <sys/debug.h>
56 #include <sys/kmem.h>
57 #include <sys/ddi.h>
58 #include <sys/sunddi.h>
59 #include <sys/conf.h>
60 #include <sys/modctl.h>
61
62 extern struct streamtab pteminfo;
63
64 static struct fmodsw fsw = {
65 "ptem",
66 &pteminfo,
67 D_MTQPAIR | D_MP
68 };
69
70 static struct modlstrmod modlstrmod = {
71 &mod_strmodops, "pty hardware emulator", &fsw
72 };
73
74 static struct modlinkage modlinkage = {
75 MODREV_1, &modlstrmod, NULL
76 };
77
78 int
_init()79 _init()
80 {
81 return (mod_install(&modlinkage));
82 }
83
84 int
_fini()85 _fini()
86 {
87 return (mod_remove(&modlinkage));
88 }
89
90 int
_info(struct modinfo * modinfop)91 _info(struct modinfo *modinfop)
92 {
93 return (mod_info(&modlinkage, modinfop));
94 }
95
96 /*
97 * stream data structure definitions
98 */
99 static int ptemopen(queue_t *, dev_t *, int, int, cred_t *);
100 static int ptemclose(queue_t *, int, cred_t *);
101 static void ptemrput(queue_t *, mblk_t *);
102 static void ptemwput(queue_t *, mblk_t *);
103 static void ptemwsrv(queue_t *);
104
105 static struct module_info ptem_info = {
106 0xabcd,
107 "ptem",
108 0,
109 512,
110 512,
111 128
112 };
113
114 static struct qinit ptemrinit = {
115 (int (*)()) ptemrput,
116 NULL,
117 ptemopen,
118 ptemclose,
119 NULL,
120 &ptem_info,
121 NULL
122 };
123
124 static struct qinit ptemwinit = {
125 (int (*)()) ptemwput,
126 (int (*)()) ptemwsrv,
127 ptemopen,
128 ptemclose,
129 nulldev,
130 &ptem_info,
131 NULL
132 };
133
134 struct streamtab pteminfo = {
135 &ptemrinit,
136 &ptemwinit,
137 NULL,
138 NULL
139 };
140
141 static void ptioc(queue_t *, mblk_t *, int);
142 static int ptemwmsg(queue_t *, mblk_t *);
143
144 /*
145 * ptemopen - open routine gets called when the module gets pushed onto the
146 * stream.
147 */
148 /* ARGSUSED */
149 static int
ptemopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)150 ptemopen(
151 queue_t *q, /* pointer to the read side queue */
152 dev_t *devp, /* pointer to stream tail's dev */
153 int oflag, /* the user open(2) supplied flags */
154 int sflag, /* open state flag */
155 cred_t *credp) /* credentials */
156 {
157 struct ptem *ntp; /* ptem entry for this PTEM module */
158 mblk_t *mop; /* an setopts mblk */
159 struct stroptions *sop;
160 struct termios *termiosp;
161 int len;
162
163 if (sflag != MODOPEN)
164 return (EINVAL);
165
166 if (q->q_ptr != NULL) {
167 /* It's already attached. */
168 return (0);
169 }
170
171 /*
172 * Allocate state structure.
173 */
174 ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);
175
176 /*
177 * Allocate a message block, used to pass the zero length message for
178 * "stty 0".
179 *
180 * NOTE: it's better to find out if such a message block can be
181 * allocated before it's needed than to not be able to
182 * deliver (for possible lack of buffers) when a hang-up
183 * occurs.
184 */
185 if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
186 kmem_free(ntp, sizeof (*ntp));
187 return (EAGAIN);
188 }
189
190 /*
191 * Initialize an M_SETOPTS message to set up hi/lo water marks on
192 * stream head read queue and add controlling tty if not set.
193 */
194 mop = allocb(sizeof (struct stroptions), BPRI_MED);
195 if (mop == NULL) {
196 freemsg(ntp->dack_ptr);
197 kmem_free(ntp, sizeof (*ntp));
198 return (EAGAIN);
199 }
200 mop->b_datap->db_type = M_SETOPTS;
201 mop->b_wptr += sizeof (struct stroptions);
202 sop = (struct stroptions *)mop->b_rptr;
203 sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
204 sop->so_hiwat = 512;
205 sop->so_lowat = 256;
206
207 /*
208 * Cross-link.
209 */
210 ntp->q_ptr = q;
211 q->q_ptr = ntp;
212 WR(q)->q_ptr = ntp;
213
214 /*
215 * Get termios defaults. These are stored as
216 * a property in the "options" node.
217 */
218 if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
219 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
220 len == sizeof (struct termios)) {
221
222 ntp->cflags = termiosp->c_cflag;
223 kmem_free(termiosp, len);
224 } else {
225 /*
226 * Gack! Whine about it.
227 */
228 cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
229 }
230 ntp->wsz.ws_row = 0;
231 ntp->wsz.ws_col = 0;
232 ntp->wsz.ws_xpixel = 0;
233 ntp->wsz.ws_ypixel = 0;
234
235 ntp->state = 0;
236
237 /*
238 * Commit to the open and send the M_SETOPTS off to the stream head.
239 */
240 qprocson(q);
241 putnext(q, mop);
242
243 return (0);
244 }
245
246
247 /*
248 * ptemclose - This routine gets called when the module gets popped off of the
249 * stream.
250 */
251 /* ARGSUSED */
252 static int
ptemclose(queue_t * q,int flag,cred_t * credp)253 ptemclose(queue_t *q, int flag, cred_t *credp)
254 {
255 struct ptem *ntp; /* ptem entry for this PTEM module */
256
257 qprocsoff(q);
258 ntp = (struct ptem *)q->q_ptr;
259 freemsg(ntp->dack_ptr);
260 kmem_free(ntp, sizeof (*ntp));
261 q->q_ptr = WR(q)->q_ptr = NULL;
262 return (0);
263 }
264
265
266 /*
267 * ptemrput - Module read queue put procedure.
268 *
269 * This is called from the module or driver downstream.
270 */
271 static void
ptemrput(queue_t * q,mblk_t * mp)272 ptemrput(queue_t *q, mblk_t *mp)
273 {
274 struct iocblk *iocp; /* M_IOCTL data */
275 struct copyresp *resp; /* transparent ioctl response struct */
276 int error;
277
278 switch (mp->b_datap->db_type) {
279 case M_DELAY:
280 case M_READ:
281 freemsg(mp);
282 break;
283
284 case M_IOCTL:
285 iocp = (struct iocblk *)mp->b_rptr;
286
287 switch (iocp->ioc_cmd) {
288 case TCSBRK:
289 /*
290 * Send a break message upstream.
291 *
292 * XXX: Shouldn't the argument come into play in
293 * determining whether or not so send an M_BREAK?
294 * It certainly does in the write-side direction.
295 */
296 error = miocpullup(mp, sizeof (int));
297 if (error != 0) {
298 miocnak(q, mp, 0, error);
299 break;
300 }
301 if (!(*(int *)mp->b_cont->b_rptr)) {
302 if (!putnextctl(q, M_BREAK)) {
303 /*
304 * Send an NAK reply back
305 */
306 miocnak(q, mp, 0, EAGAIN);
307 break;
308 }
309 }
310 /*
311 * ACK it.
312 */
313 mioc2ack(mp, NULL, 0, 0);
314 qreply(q, mp);
315 break;
316
317 case JWINSIZE:
318 case TIOCGWINSZ:
319 case TIOCSWINSZ:
320 ptioc(q, mp, RDSIDE);
321 break;
322
323 case TIOCSIGNAL:
324 /*
325 * The following subtle logic is due to the fact that
326 * `mp' may be in any one of three distinct formats:
327 *
328 * 1. A transparent M_IOCTL with an intptr_t-sized
329 * payload containing the signal number.
330 *
331 * 2. An I_STR M_IOCTL with an int-sized payload
332 * containing the signal number.
333 *
334 * 3. An M_IOCDATA with an int-sized payload
335 * containing the signal number.
336 */
337 if (iocp->ioc_count == TRANSPARENT) {
338 intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;
339
340 if (sig < 1 || sig >= NSIG) {
341 /*
342 * it's transparent with pointer
343 * to the arg
344 */
345 mcopyin(mp, NULL, sizeof (int), NULL);
346 qreply(q, mp);
347 break;
348 }
349 }
350 ptioc(q, mp, RDSIDE);
351 break;
352
353 case TIOCREMOTE:
354 if (iocp->ioc_count != TRANSPARENT)
355 ptioc(q, mp, RDSIDE);
356 else {
357 mcopyin(mp, NULL, sizeof (int), NULL);
358 qreply(q, mp);
359 }
360 break;
361
362 default:
363 putnext(q, mp);
364 break;
365 }
366 break;
367
368 case M_IOCDATA:
369 resp = (struct copyresp *)mp->b_rptr;
370 if (resp->cp_rval) {
371 /*
372 * Just free message on failure.
373 */
374 freemsg(mp);
375 break;
376 }
377
378 /*
379 * Only need to copy data for the SET case.
380 */
381 switch (resp->cp_cmd) {
382
383 case TIOCSWINSZ:
384 case TIOCSIGNAL:
385 case TIOCREMOTE:
386 ptioc(q, mp, RDSIDE);
387 break;
388
389 case JWINSIZE:
390 case TIOCGWINSZ:
391 mp->b_datap->db_type = M_IOCACK;
392 mioc2ack(mp, NULL, 0, 0);
393 qreply(q, mp);
394 break;
395
396 default:
397 freemsg(mp);
398 break;
399 }
400 break;
401
402 case M_IOCACK:
403 case M_IOCNAK:
404 /*
405 * We only pass write-side ioctls through to the master that
406 * we've already ACKed or NAKed to the stream head. Thus, we
407 * discard ones arriving from below, since they're redundant
408 * from the point of view of modules above us.
409 */
410 freemsg(mp);
411 break;
412
413 case M_HANGUP:
414 /*
415 * clear blocked state.
416 */
417 {
418 struct ptem *ntp = (struct ptem *)q->q_ptr;
419 if (ntp->state & OFLOW_CTL) {
420 ntp->state &= ~OFLOW_CTL;
421 qenable(WR(q));
422 }
423 }
424 default:
425 putnext(q, mp);
426 break;
427 }
428 }
429
430
431 /*
432 * ptemwput - Module write queue put procedure.
433 *
434 * This is called from the module or stream head upstream.
435 *
436 * XXX: This routine is quite lazy about handling allocation failures,
437 * basically just giving up and reporting failure. It really ought to
438 * set up bufcalls and only fail when it's absolutely necessary.
439 */
440 static void
ptemwput(queue_t * q,mblk_t * mp)441 ptemwput(queue_t *q, mblk_t *mp)
442 {
443 struct ptem *ntp = (struct ptem *)q->q_ptr;
444 struct iocblk *iocp; /* outgoing ioctl structure */
445 struct copyresp *resp;
446 unsigned char type = mp->b_datap->db_type;
447
448 if (type >= QPCTL) {
449 switch (type) {
450
451 case M_IOCDATA:
452 resp = (struct copyresp *)mp->b_rptr;
453 if (resp->cp_rval) {
454 /*
455 * Just free message on failure.
456 */
457 freemsg(mp);
458 break;
459 }
460
461 /*
462 * Only need to copy data for the SET case.
463 */
464 switch (resp->cp_cmd) {
465
466 case TIOCSWINSZ:
467 ptioc(q, mp, WRSIDE);
468 break;
469
470 case JWINSIZE:
471 case TIOCGWINSZ:
472 mioc2ack(mp, NULL, 0, 0);
473 qreply(q, mp);
474 break;
475
476 default:
477 freemsg(mp);
478 }
479 break;
480
481 case M_FLUSH:
482 if (*mp->b_rptr & FLUSHW) {
483 if ((ntp->state & IS_PTSTTY) &&
484 (*mp->b_rptr & FLUSHBAND))
485 flushband(q, *(mp->b_rptr + 1), 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
ptemwsrv(queue_t * q)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
ptemwmsg(queue_t * q,mblk_t * mp)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
870 default:
871 putnext(q, mp);
872 break;
873
874 }
875
876 return (1);
877 }
878
879 /*
880 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
881 */
882 static void
ptioc(queue_t * q,mblk_t * mp,int qside)883 ptioc(queue_t *q, mblk_t *mp, int qside)
884 {
885 struct ptem *tp;
886 struct iocblk *iocp;
887 struct winsize *wb;
888 struct jwinsize *jwb;
889 mblk_t *tmp;
890 mblk_t *pckt_msgp; /* message sent to the PCKT module */
891 int error;
892
893 iocp = (struct iocblk *)mp->b_rptr;
894 tp = (struct ptem *)q->q_ptr;
895
896 switch (iocp->ioc_cmd) {
897
898 case JWINSIZE:
899 /*
900 * For compatibility: If all zeros, NAK the message for dumb
901 * terminals.
902 */
903 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
904 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
905 miocnak(q, mp, 0, EINVAL);
906 return;
907 }
908
909 tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
910 if (tmp == NULL) {
911 miocnak(q, mp, 0, EAGAIN);
912 return;
913 }
914
915 if (iocp->ioc_count == TRANSPARENT)
916 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
917 else
918 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
919
920 jwb = (struct jwinsize *)mp->b_cont->b_rptr;
921 jwb->bytesx = tp->wsz.ws_col;
922 jwb->bytesy = tp->wsz.ws_row;
923 jwb->bitsx = tp->wsz.ws_xpixel;
924 jwb->bitsy = tp->wsz.ws_ypixel;
925
926 qreply(q, mp);
927 return;
928
929 case TIOCGWINSZ:
930 /*
931 * If all zeros NAK the message for dumb terminals.
932 */
933 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
934 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
935 miocnak(q, mp, 0, EINVAL);
936 return;
937 }
938
939 tmp = allocb(sizeof (struct winsize), BPRI_MED);
940 if (tmp == NULL) {
941 miocnak(q, mp, 0, EAGAIN);
942 return;
943 }
944
945 mioc2ack(mp, tmp, sizeof (struct winsize), 0);
946
947 wb = (struct winsize *)mp->b_cont->b_rptr;
948 wb->ws_row = tp->wsz.ws_row;
949 wb->ws_col = tp->wsz.ws_col;
950 wb->ws_xpixel = tp->wsz.ws_xpixel;
951 wb->ws_ypixel = tp->wsz.ws_ypixel;
952
953 qreply(q, mp);
954 return;
955
956 case TIOCSWINSZ:
957 error = miocpullup(mp, sizeof (struct winsize));
958 if (error != 0) {
959 miocnak(q, mp, 0, error);
960 return;
961 }
962
963 wb = (struct winsize *)mp->b_cont->b_rptr;
964 /*
965 * Send a SIGWINCH signal if the row/col information has
966 * changed.
967 */
968 if ((tp->wsz.ws_row != wb->ws_row) ||
969 (tp->wsz.ws_col != wb->ws_col) ||
970 (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
971 (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
972 /*
973 * SIGWINCH is always sent upstream.
974 */
975 if (qside == WRSIDE)
976 (void) putnextctl1(RD(q), M_SIG, SIGWINCH);
977 else if (qside == RDSIDE)
978 (void) putnextctl1(q, M_SIG, SIGWINCH);
979 /*
980 * Message may have come in as an M_IOCDATA; pass it
981 * to the master side as an M_IOCTL.
982 */
983 mp->b_datap->db_type = M_IOCTL;
984 if (qside == WRSIDE) {
985 /*
986 * Need a copy of this message to pass on to
987 * the PCKT module, only if the M_IOCTL
988 * orginated from the slave side.
989 */
990 if ((pckt_msgp = copymsg(mp)) == NULL) {
991 miocnak(q, mp, 0, EAGAIN);
992 return;
993 }
994 putnext(q, pckt_msgp);
995 }
996 tp->wsz.ws_row = wb->ws_row;
997 tp->wsz.ws_col = wb->ws_col;
998 tp->wsz.ws_xpixel = wb->ws_xpixel;
999 tp->wsz.ws_ypixel = wb->ws_ypixel;
1000 }
1001
1002 mioc2ack(mp, NULL, 0, 0);
1003 qreply(q, mp);
1004 return;
1005
1006 case TIOCSIGNAL: {
1007 /*
1008 * This ioctl can emanate from the master side in remote
1009 * mode only.
1010 */
1011 int sig;
1012
1013 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1014 error = miocpullup(mp, sizeof (int));
1015 if (error != 0) {
1016 miocnak(q, mp, 0, error);
1017 return;
1018 }
1019 }
1020
1021 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1022 sig = *(int *)mp->b_cont->b_rptr;
1023 else
1024 sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1025
1026 if (sig < 1 || sig >= NSIG) {
1027 miocnak(q, mp, 0, EINVAL);
1028 return;
1029 }
1030
1031 /*
1032 * Send an M_PCSIG message up the slave's read side and
1033 * respond back to the master with an ACK or NAK as
1034 * appropriate.
1035 */
1036 if (putnextctl1(q, M_PCSIG, sig) == 0) {
1037 miocnak(q, mp, 0, EAGAIN);
1038 return;
1039 }
1040
1041 mioc2ack(mp, NULL, 0, 0);
1042 qreply(q, mp);
1043 return;
1044 }
1045
1046 case TIOCREMOTE: {
1047 int onoff;
1048 mblk_t *mctlp;
1049
1050 if (DB_TYPE(mp) == M_IOCTL) {
1051 error = miocpullup(mp, sizeof (int));
1052 if (error != 0) {
1053 miocnak(q, mp, 0, error);
1054 return;
1055 }
1056 }
1057
1058 onoff = *(int *)mp->b_cont->b_rptr;
1059
1060 /*
1061 * Send M_CTL up using the iocblk format.
1062 */
1063 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1064 if (mctlp == NULL) {
1065 miocnak(q, mp, 0, EAGAIN);
1066 return;
1067 }
1068 mctlp->b_datap->db_type = M_CTL;
1069 putnext(q, mctlp);
1070
1071 /*
1072 * ACK the ioctl.
1073 */
1074 mioc2ack(mp, NULL, 0, 0);
1075 qreply(q, mp);
1076
1077 /*
1078 * Record state change.
1079 */
1080 if (onoff)
1081 tp->state |= REMOTEMODE;
1082 else
1083 tp->state &= ~REMOTEMODE;
1084 return;
1085 }
1086
1087 default:
1088 putnext(q, mp);
1089 return;
1090 }
1091 }
1092