blob: e4dc15a3ac4f67149e79c472fd65d996ea469088 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
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.
Andy Fiddaman6cfa0a72018-05-30 00:15:35 +000029 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070030 */
31
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070032/*
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
61extern struct streamtab pteminfo;
62
63static struct fmodsw fsw = {
64 "ptem",
65 &pteminfo,
Andy Fiddaman6cfa0a72018-05-30 00:15:35 +000066 D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070067};
68
69static struct modlstrmod modlstrmod = {
70 &mod_strmodops, "pty hardware emulator", &fsw
71};
72
73static struct modlinkage modlinkage = {
74 MODREV_1, &modlstrmod, NULL
75};
76
77int
78_init()
79{
80 return (mod_install(&modlinkage));
81}
82
83int
84_fini()
85{
86 return (mod_remove(&modlinkage));
87}
88
89int
90_info(struct modinfo *modinfop)
91{
92 return (mod_info(&modlinkage, modinfop));
93}
94
95/*
96 * stream data structure definitions
97 */
98static int ptemopen(queue_t *, dev_t *, int, int, cred_t *);
99static int ptemclose(queue_t *, int, cred_t *);
100static void ptemrput(queue_t *, mblk_t *);
101static void ptemwput(queue_t *, mblk_t *);
102static void ptemwsrv(queue_t *);
103
104static struct module_info ptem_info = {
105 0xabcd,
106 "ptem",
107 0,
Richard Lowe2463e922017-06-15 13:29:55 -0400108 _TTY_BUFSIZ,
109 _TTY_BUFSIZ,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700110 128
111};
112
113static struct qinit ptemrinit = {
114 (int (*)()) ptemrput,
115 NULL,
116 ptemopen,
117 ptemclose,
118 NULL,
119 &ptem_info,
120 NULL
121};
122
123static struct qinit ptemwinit = {
124 (int (*)()) ptemwput,
125 (int (*)()) ptemwsrv,
126 ptemopen,
127 ptemclose,
128 nulldev,
129 &ptem_info,
130 NULL
131};
132
133struct streamtab pteminfo = {
134 &ptemrinit,
135 &ptemwinit,
136 NULL,
137 NULL
138};
139
140static void ptioc(queue_t *, mblk_t *, int);
141static 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 */
148static int
149ptemopen(
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;
Richard Lowe2463e922017-06-15 13:29:55 -0400203 sop->so_hiwat = _TTY_BUFSIZ;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700204 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 */
251static int
252ptemclose(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 */
270static void
271ptemrput(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 master 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 }
Toomas Soomeb80bb912017-07-15 13:48:43 +0300423 /* FALLTHROUGH */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700424 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 */
440static void
441ptemwput(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) {
Richard Lowe2463e922017-06-15 13:29:55 -0400483 if ((ntp->state & IS_PTSTTY) &&
484 (*mp->b_rptr & FLUSHBAND))
485 flushband(q, *(mp->b_rptr + 1),
486 FLUSHDATA);
487 else
488 flushq(q, FLUSHDATA);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700489 }
490 putnext(q, mp);
491 break;
492
493 case M_READ:
494 freemsg(mp);
495 break;
496
497 case M_STOP:
498 /*
499 * Set the output flow control state.
500 */
501 ntp->state |= OFLOW_CTL;
502 putnext(q, mp);
503 break;
504
505 case M_START:
506 /*
507 * Relieve the output flow control state.
508 */
509 ntp->state &= ~OFLOW_CTL;
510 putnext(q, mp);
511 qenable(q);
512 break;
513 default:
514 putnext(q, mp);
515 break;
516 }
517 return;
518 }
519 /*
520 * If our queue is nonempty or flow control persists
521 * downstream or module in stopped state, queue this message.
522 */
523 if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
524 /*
525 * Exception: ioctls, except for those defined to
526 * take effect after output has drained, should be
527 * processed immediately.
528 */
529 switch (type) {
530
531 case M_IOCTL:
532 iocp = (struct iocblk *)mp->b_rptr;
533 switch (iocp->ioc_cmd) {
534 /*
535 * Queue these.
536 */
537 case TCSETSW:
538 case TCSETSF:
539 case TCSETAW:
540 case TCSETAF:
541 case TCSBRK:
542 break;
543
544 /*
545 * Handle all others immediately.
546 */
547 default:
548 (void) ptemwmsg(q, mp);
549 return;
550 }
551 break;
552
553 case M_DELAY: /* tty delays not supported */
554 freemsg(mp);
555 return;
556
557 case M_DATA:
558 if ((mp->b_wptr - mp->b_rptr) < 0) {
559 /*
560 * Free all bad length messages.
561 */
562 freemsg(mp);
563 return;
564 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
565 if (!(ntp->state & IS_PTSTTY)) {
566 freemsg(mp);
567 return;
568 }
569 }
570 }
571 (void) putq(q, mp);
572 return;
573 }
574 /*
575 * fast path into ptemwmsg to dispose of mp.
576 */
577 if (!ptemwmsg(q, mp))
578 (void) putq(q, mp);
579}
580
581/*
582 * ptem write queue service procedure.
583 */
584static void
585ptemwsrv(queue_t *q)
586{
587 mblk_t *mp;
588
589 while ((mp = getq(q)) != NULL) {
590 if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
591 (void) putbq(q, mp);
592 break;
593 }
594 }
595}
596
597
598/*
599 * This routine is called from both ptemwput and ptemwsrv to do the
600 * actual work of dealing with mp. ptmewput will have already
601 * dealt with high priority messages.
602 *
603 * Return 1 if the message was processed completely and 0 if not.
604 */
605static int
606ptemwmsg(queue_t *q, mblk_t *mp)
607{
608 struct ptem *ntp = (struct ptem *)q->q_ptr;
609 struct iocblk *iocp; /* outgoing ioctl structure */
610 struct termio *termiop;
611 struct termios *termiosp;
612 mblk_t *dack_ptr; /* disconnect message ACK block */
613 mblk_t *pckt_msgp; /* message sent to the PCKT module */
614 mblk_t *dp; /* ioctl reply data */
615 tcflag_t cflags;
616 int error;
617
618 switch (mp->b_datap->db_type) {
619
620 case M_IOCTL:
621 /*
622 * Note: for each "set" type operation a copy
623 * of the M_IOCTL message is made and passed
624 * downstream. Eventually the PCKT module, if
625 * it has been pushed, should pick up this message.
626 * If the PCKT module has not been pushed the master
627 * side stream head will free it.
628 */
629 iocp = (struct iocblk *)mp->b_rptr;
630 switch (iocp->ioc_cmd) {
631
632 case TCSETAF:
633 case TCSETSF:
634 /*
635 * Flush the read queue.
636 */
637 if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
638 miocnak(q, mp, 0, EAGAIN);
639 break;
640 }
641 /* FALLTHROUGH */
642
643 case TCSETA:
644 case TCSETAW:
645 case TCSETS:
646 case TCSETSW:
647
648 switch (iocp->ioc_cmd) {
649 case TCSETAF:
650 case TCSETA:
651 case TCSETAW:
652 error = miocpullup(mp, sizeof (struct termio));
653 if (error != 0) {
654 miocnak(q, mp, 0, error);
655 goto out;
656 }
657 cflags = ((struct termio *)
658 mp->b_cont->b_rptr)->c_cflag;
659 ntp->cflags =
660 (ntp->cflags & 0xffff0000 | cflags);
661 break;
662
663 case TCSETSF:
664 case TCSETS:
665 case TCSETSW:
666 error = miocpullup(mp, sizeof (struct termios));
667 if (error != 0) {
668 miocnak(q, mp, 0, error);
669 goto out;
670 }
671 cflags = ((struct termios *)
672 mp->b_cont->b_rptr)->c_cflag;
673 ntp->cflags = cflags;
674 break;
675 }
676
677 if ((cflags & CBAUD) == B0) {
678 /*
679 * Hang-up: Send a zero length message.
680 */
681 dack_ptr = ntp->dack_ptr;
682
683 if (dack_ptr) {
684 ntp->dack_ptr = NULL;
685 /*
686 * Send a zero length message
687 * downstream.
688 */
689 putnext(q, dack_ptr);
690 }
691 } else {
692 /*
693 * Make a copy of this message and pass it on
694 * to the PCKT module.
695 */
696 if ((pckt_msgp = copymsg(mp)) == NULL) {
697 miocnak(q, mp, 0, EAGAIN);
698 break;
699 }
700 putnext(q, pckt_msgp);
701 }
702 /*
703 * Send ACK upstream.
704 */
705 mioc2ack(mp, NULL, 0, 0);
706 qreply(q, mp);
707out:
708 break;
709
710 case TCGETA:
711 dp = allocb(sizeof (struct termio), BPRI_MED);
712 if (dp == NULL) {
713 miocnak(q, mp, 0, EAGAIN);
714 break;
715 }
716 termiop = (struct termio *)dp->b_rptr;
717 termiop->c_cflag = (ushort_t)ntp->cflags;
718 mioc2ack(mp, dp, sizeof (struct termio), 0);
719 qreply(q, mp);
720 break;
721
722 case TCGETS:
723 dp = allocb(sizeof (struct termios), BPRI_MED);
724 if (dp == NULL) {
725 miocnak(q, mp, 0, EAGAIN);
726 break;
727 }
728 termiosp = (struct termios *)dp->b_rptr;
729 termiosp->c_cflag = ntp->cflags;
730 mioc2ack(mp, dp, sizeof (struct termios), 0);
731 qreply(q, mp);
732 break;
733
734 case TCSBRK:
735 error = miocpullup(mp, sizeof (int));
736 if (error != 0) {
737 miocnak(q, mp, 0, error);
738 break;
739 }
740
741 /*
742 * Need a copy of this message to pass it on to
743 * the PCKT module.
744 */
745 if ((pckt_msgp = copymsg(mp)) == NULL) {
746 miocnak(q, mp, 0, EAGAIN);
747 break;
748 }
749 /*
750 * Send a copy of the M_IOCTL to the PCKT module.
751 */
752 putnext(q, pckt_msgp);
753
754 /*
755 * TCSBRK meaningful if data part of message is 0
756 * cf. termio(7).
757 */
758 if (!(*(int *)mp->b_cont->b_rptr))
759 (void) putnextctl(q, M_BREAK);
760 /*
761 * ACK the ioctl.
762 */
763 mioc2ack(mp, NULL, 0, 0);
764 qreply(q, mp);
765 break;
766
767 case JWINSIZE:
768 case TIOCGWINSZ:
769 case TIOCSWINSZ:
770 ptioc(q, mp, WRSIDE);
771 break;
772
773 case TIOCSTI:
774 /*
775 * Simulate typing of a character at the terminal. In
776 * all cases, we acknowledge the ioctl and pass a copy
777 * of it along for the PCKT module to encapsulate. If
778 * not in remote mode, we also process the ioctl
779 * itself, looping the character given as its argument
780 * back around to the read side.
781 */
782
783 /*
784 * Need a copy of this message to pass on to the PCKT
785 * module.
786 */
787 if ((pckt_msgp = copymsg(mp)) == NULL) {
788 miocnak(q, mp, 0, EAGAIN);
789 break;
790 }
791 if ((ntp->state & REMOTEMODE) == 0) {
792 mblk_t *bp;
793
794 error = miocpullup(mp, sizeof (char));
795 if (error != 0) {
796 freemsg(pckt_msgp);
797 miocnak(q, mp, 0, error);
798 break;
799 }
800
801 /*
802 * The permission checking has already been
803 * done at the stream head, since it has to be
804 * done in the context of the process doing
805 * the call.
806 */
807 if ((bp = allocb(1, BPRI_MED)) == NULL) {
808 freemsg(pckt_msgp);
809 miocnak(q, mp, 0, EAGAIN);
810 break;
811 }
812 /*
813 * XXX: Is EAGAIN really the right response to
814 * flow control blockage?
815 */
816 if (!bcanputnext(RD(q), mp->b_band)) {
817 freemsg(bp);
818 freemsg(pckt_msgp);
819 miocnak(q, mp, 0, EAGAIN);
820 break;
821 }
822 *bp->b_wptr++ = *mp->b_cont->b_rptr;
823 qreply(q, bp);
824 }
825
826 putnext(q, pckt_msgp);
827 mioc2ack(mp, NULL, 0, 0);
828 qreply(q, mp);
829 break;
830
831 case PTSSTTY:
832 if (ntp->state & IS_PTSTTY) {
833 miocnak(q, mp, 0, EEXIST);
834 } else {
835 ntp->state |= IS_PTSTTY;
836 mioc2ack(mp, NULL, 0, 0);
837 qreply(q, mp);
838 }
839 break;
840
841 default:
842 /*
843 * End of the line. The slave driver doesn't see any
844 * ioctls that we don't explicitly pass along to it.
845 */
846 miocnak(q, mp, 0, EINVAL);
847 break;
848 }
849 break;
850
851 case M_DELAY: /* tty delays not supported */
852 freemsg(mp);
853 break;
854
855 case M_DATA:
856 if ((mp->b_wptr - mp->b_rptr) < 0) {
857 /*
858 * Free all bad length messages.
859 */
860 freemsg(mp);
861 break;
862 } else if ((mp->b_wptr - mp->b_rptr) == 0) {
863 if (!(ntp->state & IS_PTSTTY)) {
864 freemsg(mp);
865 break;
866 }
867 }
868 if (ntp->state & OFLOW_CTL)
869 return (0);
Toomas Soomeb80bb912017-07-15 13:48:43 +0300870 /* FALLTHROUGH */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700871
872 default:
873 putnext(q, mp);
874 break;
875
876 }
877
878 return (1);
879}
880
881/*
882 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
883 */
884static void
885ptioc(queue_t *q, mblk_t *mp, int qside)
886{
887 struct ptem *tp;
888 struct iocblk *iocp;
889 struct winsize *wb;
890 struct jwinsize *jwb;
891 mblk_t *tmp;
892 mblk_t *pckt_msgp; /* message sent to the PCKT module */
893 int error;
894
895 iocp = (struct iocblk *)mp->b_rptr;
896 tp = (struct ptem *)q->q_ptr;
897
898 switch (iocp->ioc_cmd) {
899
900 case JWINSIZE:
901 /*
902 * For compatibility: If all zeros, NAK the message for dumb
903 * terminals.
904 */
905 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
906 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
907 miocnak(q, mp, 0, EINVAL);
908 return;
909 }
910
911 tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
912 if (tmp == NULL) {
913 miocnak(q, mp, 0, EAGAIN);
914 return;
915 }
916
917 if (iocp->ioc_count == TRANSPARENT)
918 mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
919 else
920 mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);
921
922 jwb = (struct jwinsize *)mp->b_cont->b_rptr;
923 jwb->bytesx = tp->wsz.ws_col;
924 jwb->bytesy = tp->wsz.ws_row;
925 jwb->bitsx = tp->wsz.ws_xpixel;
926 jwb->bitsy = tp->wsz.ws_ypixel;
927
928 qreply(q, mp);
929 return;
930
931 case TIOCGWINSZ:
932 /*
933 * If all zeros NAK the message for dumb terminals.
934 */
935 if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
936 (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
937 miocnak(q, mp, 0, EINVAL);
938 return;
939 }
940
941 tmp = allocb(sizeof (struct winsize), BPRI_MED);
942 if (tmp == NULL) {
943 miocnak(q, mp, 0, EAGAIN);
944 return;
945 }
946
947 mioc2ack(mp, tmp, sizeof (struct winsize), 0);
948
949 wb = (struct winsize *)mp->b_cont->b_rptr;
950 wb->ws_row = tp->wsz.ws_row;
951 wb->ws_col = tp->wsz.ws_col;
952 wb->ws_xpixel = tp->wsz.ws_xpixel;
953 wb->ws_ypixel = tp->wsz.ws_ypixel;
954
955 qreply(q, mp);
956 return;
957
958 case TIOCSWINSZ:
959 error = miocpullup(mp, sizeof (struct winsize));
960 if (error != 0) {
961 miocnak(q, mp, 0, error);
962 return;
963 }
964
965 wb = (struct winsize *)mp->b_cont->b_rptr;
966 /*
967 * Send a SIGWINCH signal if the row/col information has
968 * changed.
969 */
970 if ((tp->wsz.ws_row != wb->ws_row) ||
971 (tp->wsz.ws_col != wb->ws_col) ||
972 (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
973 (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
974 /*
975 * SIGWINCH is always sent upstream.
976 */
977 if (qside == WRSIDE)
978 (void) putnextctl1(RD(q), M_SIG, SIGWINCH);
979 else if (qside == RDSIDE)
980 (void) putnextctl1(q, M_SIG, SIGWINCH);
981 /*
982 * Message may have come in as an M_IOCDATA; pass it
983 * to the master side as an M_IOCTL.
984 */
985 mp->b_datap->db_type = M_IOCTL;
986 if (qside == WRSIDE) {
987 /*
988 * Need a copy of this message to pass on to
989 * the PCKT module, only if the M_IOCTL
990 * orginated from the slave side.
991 */
992 if ((pckt_msgp = copymsg(mp)) == NULL) {
993 miocnak(q, mp, 0, EAGAIN);
994 return;
995 }
996 putnext(q, pckt_msgp);
997 }
998 tp->wsz.ws_row = wb->ws_row;
999 tp->wsz.ws_col = wb->ws_col;
1000 tp->wsz.ws_xpixel = wb->ws_xpixel;
1001 tp->wsz.ws_ypixel = wb->ws_ypixel;
1002 }
1003
1004 mioc2ack(mp, NULL, 0, 0);
1005 qreply(q, mp);
1006 return;
1007
1008 case TIOCSIGNAL: {
1009 /*
1010 * This ioctl can emanate from the master side in remote
1011 * mode only.
1012 */
1013 int sig;
1014
1015 if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
1016 error = miocpullup(mp, sizeof (int));
1017 if (error != 0) {
1018 miocnak(q, mp, 0, error);
1019 return;
1020 }
1021 }
1022
1023 if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
1024 sig = *(int *)mp->b_cont->b_rptr;
1025 else
1026 sig = (int)*(intptr_t *)mp->b_cont->b_rptr;
1027
1028 if (sig < 1 || sig >= NSIG) {
1029 miocnak(q, mp, 0, EINVAL);
1030 return;
1031 }
1032
1033 /*
1034 * Send an M_PCSIG message up the slave's read side and
1035 * respond back to the master with an ACK or NAK as
1036 * appropriate.
1037 */
1038 if (putnextctl1(q, M_PCSIG, sig) == 0) {
1039 miocnak(q, mp, 0, EAGAIN);
1040 return;
1041 }
1042
1043 mioc2ack(mp, NULL, 0, 0);
1044 qreply(q, mp);
1045 return;
Richard Lowe2463e922017-06-15 13:29:55 -04001046 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001047
1048 case TIOCREMOTE: {
1049 int onoff;
1050 mblk_t *mctlp;
1051
1052 if (DB_TYPE(mp) == M_IOCTL) {
1053 error = miocpullup(mp, sizeof (int));
1054 if (error != 0) {
1055 miocnak(q, mp, 0, error);
1056 return;
1057 }
1058 }
1059
1060 onoff = *(int *)mp->b_cont->b_rptr;
1061
1062 /*
1063 * Send M_CTL up using the iocblk format.
1064 */
1065 mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
1066 if (mctlp == NULL) {
1067 miocnak(q, mp, 0, EAGAIN);
1068 return;
1069 }
1070 mctlp->b_datap->db_type = M_CTL;
1071 putnext(q, mctlp);
1072
1073 /*
1074 * ACK the ioctl.
1075 */
1076 mioc2ack(mp, NULL, 0, 0);
1077 qreply(q, mp);
1078
1079 /*
1080 * Record state change.
1081 */
1082 if (onoff)
1083 tp->state |= REMOTEMODE;
1084 else
1085 tp->state &= ~REMOTEMODE;
1086 return;
Richard Lowe2463e922017-06-15 13:29:55 -04001087 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001088
1089 default:
1090 putnext(q, mp);
1091 return;
1092 }
1093}