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 }