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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
29 * This module implements the services provided by the rlogin daemon
30 * after the connection is set up. Mainly this means responding to
31 * interrupts and window size changes. It begins operation in "disabled"
32 * state, and sends a T_DATA_REQ to the daemon to indicate that it is
33 * in place and ready to be enabled. The daemon can then know when all
34 * data which sneaked passed rlmod (before it was pushed) has been received.
35 * The daemon may process this data, or send data back to be inserted in
36 * the read queue at the head with the RL_IOC_ENABLE ioctl.
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>
45 #include <sys/errno.h>
47 #include <sys/sunddi.h>
48 #include <sys/tihdr.h>
51 #include <sys/debug.h>
52 #include <sys/modctl.h>
53 #include <sys/vtrace.h>
54 #include <sys/rlioctl.h>
55 #include <sys/termios.h>
56 #include <sys/termio.h>
57 #include <sys/byteorder.h>
58 #include <sys/cmn_err.h>
59 #include <sys/cryptmod.h>
61 extern struct streamtab rloginmodinfo
;
63 static struct fmodsw fsw
= {
70 * Module linkage information for the kernel.
73 static struct modlstrmod modlstrmod
= {
79 static struct modlinkage modlinkage
= {
80 MODREV_1
, &modlstrmod
, NULL
87 return (mod_install(&modlinkage
));
93 return (mod_remove(&modlinkage
));
97 _info(struct modinfo
*modinfop
)
99 return (mod_info(&modlinkage
, modinfop
));
102 struct rlmod_info
; /* forward reference for function prototype */
104 static int rlmodopen(queue_t
*, dev_t
*, int, int, cred_t
*);
105 static int rlmodclose(queue_t
*, int, cred_t
*);
106 static int rlmodrput(queue_t
*, mblk_t
*);
107 static int rlmodrsrv(queue_t
*);
108 static int rlmodwput(queue_t
*, mblk_t
*);
109 static int rlmodwsrv(queue_t
*);
110 static int rlmodrmsg(queue_t
*, mblk_t
*);
111 static mblk_t
*make_expmblk(char);
112 static int rlwinctl(queue_t
*, mblk_t
*);
113 static mblk_t
*rlwinsetup(queue_t
*, mblk_t
*, unsigned char *);
115 static void rlmod_timer(void *);
116 static void rlmod_buffer(void *);
117 static boolean_t
tty_flow(queue_t
*, struct rlmod_info
*, mblk_t
*);
118 static boolean_t
rlmodwioctl(queue_t
*, mblk_t
*);
119 static void recover(queue_t
*, mblk_t
*, size_t);
120 static void recover1(queue_t
*, size_t);
123 #define SIMWAIT (1*hz)
126 * Stream module data structure definitions.
127 * generally pushed onto tcp by rlogin daemon
130 static struct module_info rloginmodiinfo
= {
131 RLMOD_ID
, /* module id number */
132 "rlmod", /* module name */
133 0, /* minimum packet size */
134 INFPSZ
, /* maximum packet size */
135 512, /* hi-water mark */
136 256 /* lo-water mark */
139 static struct qinit rloginmodrinit
= {
149 static struct qinit rloginmodwinit
= {
159 struct streamtab rloginmodinfo
= {
167 * Per-instance state struct for the rloginmod module.
172 bufcall_id_t wbufcid
;
173 bufcall_id_t rbufcid
;
174 timeout_id_t wtimoutid
;
175 timeout_id_t rtimoutid
;
182 mblk_t
*wndw_sz_hd_mp
;
188 #define RL_DISABLED 0x1
189 #define RL_IOCPASSTHRU 0x2
193 dummy_callback(void *arg
)
197 * rlmodopen - open routine gets called when the
198 * module gets pushed onto the stream.
202 rlmodopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*cred
)
204 struct rlmod_info
*rmip
;
205 union T_primitives
*tp
;
209 if (sflag
!= MODOPEN
)
212 if (q
->q_ptr
!= NULL
) {
213 /* It's already attached. */
218 * Allocate state structure.
220 rmip
= kmem_zalloc(sizeof (*rmip
), KM_SLEEP
);
228 rmip
->stopmode
= TIOCPKT_DOSTOP
;
229 rmip
->startc
= CTRL('q');
230 rmip
->stopc
= CTRL('s');
231 rmip
->oobdata
[0] = (char)TIOCPKT_WINDOW
;
232 rmip
->wndw_sz_hd_mp
= NULL
;
234 * Allow only non-M_DATA blocks to pass up to in.rlogind until
235 * it is ready for M_DATA (indicated by RL_IOC_ENABLE).
237 rmip
->flags
|= RL_DISABLED
;
242 * Since TCP operates in the TLI-inspired brain-dead fashion,
243 * the connection will revert to bound state if the connection
244 * is reset by the client. We must send a T_UNBIND_REQ in
245 * that case so the port doesn't get "wedged" (preventing
246 * inetd from being able to restart the listener). Allocate
247 * it here, so that we don't need to worry about allocb()
250 while ((rmip
->unbind_mp
= allocb(sizeof (union T_primitives
),
252 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
253 BPRI_HI
, dummy_callback
, NULL
);
261 rmip
->unbind_mp
->b_wptr
= rmip
->unbind_mp
->b_rptr
+
262 sizeof (struct T_unbind_req
);
263 rmip
->unbind_mp
->b_datap
->db_type
= M_PROTO
;
264 tp
= (union T_primitives
*)rmip
->unbind_mp
->b_rptr
;
265 tp
->type
= T_UNBIND_REQ
;
268 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
269 * read queue since only write queue can get T_DATA_REQ).
270 * Readstream routine in the daemon will do a getmsg() till
271 * it receives this proto message.
273 while ((bp
= allocb(sizeof (union T_primitives
), BPRI_HI
)) == NULL
) {
274 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
275 BPRI_HI
, dummy_callback
, NULL
);
283 bp
->b_datap
->db_type
= M_PROTO
;
284 bp
->b_wptr
= bp
->b_rptr
+ sizeof (union T_primitives
);
285 tp
= (union T_primitives
*)bp
->b_rptr
;
286 tp
->type
= T_DATA_REQ
;
287 tp
->data_req
.MORE_flag
= 0;
293 if (rmip
->unbind_mp
!= NULL
) {
294 freemsg(rmip
->unbind_mp
);
296 kmem_free(rmip
, sizeof (struct rlmod_info
));
304 * rlmodclose - This routine gets called when the module
305 * gets popped off of the stream.
310 rlmodclose(queue_t
*q
, int flag
, cred_t
*credp
)
312 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
316 * Flush any write-side data downstream. Ignoring flow
317 * control at this point is known to be safe because the
318 * M_HANGUP below poisons the stream such that no modules can
321 while (mp
= getq(WR(q
)))
324 /* Poison the stream head so that we can't be pushed again. */
325 (void) putnextctl(q
, M_HANGUP
);
329 qunbufcall(q
, rmip
->wbufcid
);
333 qunbufcall(q
, rmip
->rbufcid
);
336 if (rmip
->wtimoutid
) {
337 (void) quntimeout(q
, rmip
->wtimoutid
);
340 if (rmip
->rtimoutid
) {
341 (void) quntimeout(q
, rmip
->rtimoutid
);
345 if (rmip
->unbind_mp
!= NULL
) {
346 freemsg(rmip
->unbind_mp
);
349 if (rmip
->wndw_sz_hd_mp
!= NULL
) {
350 freemsg(rmip
->wndw_sz_hd_mp
);
353 kmem_free(q
->q_ptr
, sizeof (struct rlmod_info
));
354 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
359 * rlmodrput - Module read queue put procedure.
360 * This is called from the module or
365 rlmodrput(queue_t
*q
, mblk_t
*mp
)
367 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
368 union T_primitives
*tip
;
370 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_IN
, "rlmodrput start: "
371 "q %p, mp %p", q
, mp
);
374 /* if low (normal) priority... */
375 if ((mp
->b_datap
->db_type
< QPCTL
) &&
376 /* ...and data is already queued... */
378 /* ...or currently disabled and this is M_DATA... */
379 ((rmip
->flags
& RL_DISABLED
) &&
380 (mp
->b_datap
->db_type
== M_DATA
)))) {
381 /* ...delay delivery of the message */
383 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_OUT
,
384 "rlmodrput end: q %p, mp %p, %s", q
, mp
, "flow");
388 switch (mp
->b_datap
->db_type
) {
392 tip
= (union T_primitives
*)mp
->b_rptr
;
397 /* Make into M_HANGUP and putnext */
398 mp
->b_datap
->db_type
= M_HANGUP
;
399 mp
->b_wptr
= mp
->b_rptr
;
405 * If we haven't already, send T_UNBIND_REQ to prevent
406 * TCP from going into "BOUND" state and locking up the
409 if (tip
->type
== T_DISCON_IND
&& rmip
->unbind_mp
!=
412 qreply(q
, rmip
->unbind_mp
);
413 rmip
->unbind_mp
= NULL
;
420 * We only get T_OK_ACK when we issue the unbind, and it can
424 ASSERT(rmip
->unbind_mp
== NULL
);
430 "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
437 if (canputnext(q
) && q
->q_first
== NULL
) {
438 (void) rlmodrmsg(q
, mp
);
446 * Since M_FLUSH came from TCP, we mark it bound for
447 * daemon, not tty. This only happens when TCP expects
448 * to do a connection reset.
450 mp
->b_flag
|= MSGMARK
;
451 if (*mp
->b_rptr
& FLUSHR
)
462 if (mp
->b_datap
->db_type
<= QPCTL
&& !canputnext(q
))
470 cmn_err(CE_NOTE
, "rlmodrput: unexpected msg type 0x%x",
471 mp
->b_datap
->db_type
);
475 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_OUT
, "rlmodrput end: q %p, "
476 "mp %p, %s", q
, mp
, "done");
481 * rlmodrsrv - module read service procedure
484 rlmodrsrv(queue_t
*q
)
487 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
488 union T_primitives
*tip
;
490 TRACE_1(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_IN
, "rlmodrsrv start: "
492 while ((mp
= getq(q
)) != NULL
) {
494 switch (mp
->b_datap
->db_type
) {
496 if (rmip
->flags
& RL_DISABLED
) {
498 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
499 "rlmodrsrv end: q %p, mp %p, %s", q
, mp
,
503 if (!canputnext(q
)) {
505 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
506 "rlmodrsrv end: q %p, mp %p, %s",
507 q
, mp
, "!canputnext");
510 if (!rlmodrmsg(q
, mp
)) {
511 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
512 "rlmodrsrv end: q %p, mp %p, %s",
513 q
, mp
, "!rlmodrmsg");
519 tip
= (union T_primitives
*)mp
->b_rptr
;
524 /* Make into M_HANGUP and putnext */
525 mp
->b_datap
->db_type
= M_HANGUP
;
526 mp
->b_wptr
= mp
->b_rptr
;
532 * If we haven't already, send T_UNBIND_REQ
533 * to prevent TCP from going into "BOUND"
534 * state and locking up the port.
536 if (tip
->type
== T_DISCON_IND
&&
537 rmip
->unbind_mp
!= NULL
) {
539 qreply(q
, rmip
->unbind_mp
);
540 rmip
->unbind_mp
= NULL
;
547 * We only get T_OK_ACK when we issue the unbind, and
548 * it can be ignored safely.
551 ASSERT(rmip
->unbind_mp
== NULL
);
557 "rlmodrsrv: got 0x%x type PROTO msg",
564 if (!canputnext(q
)) {
566 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
567 "rlmodrsrv end: q %p, mp %p, %s",
568 q
, mp
, "!canputnext M_SETOPTS");
577 "rlmodrsrv: unexpected msg type 0x%x",
578 mp
->b_datap
->db_type
);
584 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
, "rlmodrsrv end: q %p, "
585 "mp %p, %s", q
, mp
, "empty");
591 * rlmodwput - Module write queue put procedure.
592 * All non-zero messages are send downstream unchanged
595 rlmodwput(queue_t
*q
, mblk_t
*mp
)
598 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
602 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_IN
, "rlmodwput start: "
603 "q %p, mp %p", q
, mp
);
605 if (rmip
->rl_expdat
) {
607 * call make_expmblk to create an expedited
610 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
612 if (!canputnext(q
)) {
614 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
615 "rlmodwput end: q %p, mp %p, %s",
616 q
, mp
, "expdata && !canputnext");
619 if ((tmpmp
= make_expmblk(cntl
))) {
623 recover1(q
, sizeof (mblk_t
)); /* XXX.sparker */
627 if ((q
->q_first
|| rmip
->rl_expdat
) && mp
->b_datap
->db_type
< QPCTL
) {
629 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
, "rlmodwput end: "
630 "q %p, mp %p, %s", q
, mp
, "queued data");
633 switch (mp
->b_datap
->db_type
) {
644 * We must take care to create and forward out-of-band data
645 * indicating the flush to the far side.
648 *mp
->b_rptr
&= ~FLUSHW
;
652 * Since all rlogin protocol data is sent in this
653 * direction as urgent data, and TCP does not flush
654 * urgent data, it is okay to actually forward this
655 * flush. (telmod cannot.)
657 flushq(q
, FLUSHDATA
);
659 * The putnextctl1() call can only fail if we're
660 * out of memory. Ideally, we might set a state
661 * bit and reschedule ourselves when memory
662 * becomes available, so we make sure not to miss
663 * sending the FLUSHW to TCP before the urgent
664 * byte. Not doing this just means in some cases
665 * a bit more trash passes before the flush takes
668 (void) putnextctl1(q
, M_FLUSH
, FLUSHW
);
670 * Notify peer of the write flush request.
672 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
673 if (!canputnext(q
)) {
674 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
675 "rlmodwput end: q %p, mp %p, %s",
676 q
, mp
, "flushw && !canputnext");
679 if ((mp
= make_expmblk(cntl
)) == NULL
) {
681 recover1(q
, sizeof (mblk_t
));
682 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
683 "rlmodwput end: q %p, mp %p, %s",
684 q
, mp
, "!make_expmblk");
692 if (!rlmodwioctl(q
, mp
))
697 switch (((union T_primitives
*)mp
->b_rptr
)->type
) {
707 "rlmodwput: unexpected TPI primitive 0x%x",
708 ((union T_primitives
*)mp
->b_rptr
)->type
);
715 if (((struct T_exdata_req
*)mp
->b_rptr
)->PRIM_type
==
719 /* XXX.sparker Log unexpected message */
727 "rlmodwput: unexpected msg type 0x%x",
728 mp
->b_datap
->db_type
);
733 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
, "rlmodwput end: "
734 "q %p, mp %p, %s", q
, mp
, "done");
739 * rlmodwsrv - module write service procedure
742 rlmodwsrv(queue_t
*q
)
746 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
748 TRACE_1(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_IN
, "rlmodwsrv "
750 if (rmip
->rl_expdat
) {
752 * call make_expmblk to create an expedited
755 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
756 if (!canputnext(q
)) {
757 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
758 "rlmodwsrv end: q %p, mp %p, %s",
759 q
, NULL
, "!canputnext && expdat");
762 if ((tmpmp
= make_expmblk(cntl
))) {
766 recover1(q
, sizeof (mblk_t
));
767 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
768 "rlmodwsrv end: q %p, mp %p, %s",
769 q
, NULL
, "!make_expmblk");
773 while ((mp
= getq(q
)) != NULL
) {
775 if (!canputnext(q
) || rmip
->rl_expdat
) {
777 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
778 "rlmodwsrv end: q %p, mp %p, %s",
779 q
, mp
, "!canputnext || expdat");
782 if (mp
->b_datap
->db_type
== M_IOCTL
) {
783 if (!rlmodwioctl(q
, mp
)) {
784 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
785 "rlmodwsrv end: q %p, mp %p, %s",
786 q
, mp
, "!rlmodwioctl");
794 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
, "rlmodwsrv end: q %p, "
795 "mp %p, %s", q
, mp
, "done");
800 * This routine returns a message block with an expedited
804 make_expmblk(char cntl
)
808 struct T_exdata_req
*data_req
;
810 bp
= allocb(sizeof (struct T_exdata_req
), BPRI_MED
);
813 if ((mp
= allocb(sizeof (char), BPRI_MED
)) == NULL
) {
817 bp
->b_datap
->db_type
= M_PROTO
;
818 data_req
= (struct T_exdata_req
*)bp
->b_rptr
;
819 data_req
->PRIM_type
= T_EXDATA_REQ
;
820 data_req
->MORE_flag
= 0;
822 bp
->b_wptr
+= sizeof (struct T_exdata_req
);
824 * Send a 1 byte data message block with appropriate
827 mp
->b_datap
->db_type
= M_DATA
;
828 mp
->b_wptr
= mp
->b_rptr
+ 1;
829 (*(char *)(mp
->b_rptr
)) = cntl
;
834 * This routine parses M_DATA messages checking for window size protocol
835 * from a given message block. It returns TRUE if no resource exhaustion
836 * conditions are found. This is for use in the service procedure, which
837 * needs to know whether to continue, or stop processing the queue.
840 rlmodrmsg(queue_t
*q
, mblk_t
*mp
)
842 unsigned char *tmp
, *tmp1
;
845 ssize_t count
, newcount
= 0;
846 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
849 * Eliminate any zero length messages here, so we don't filter EOFs
852 if (msgdsize(mp
) == 0) {
853 ASSERT(rmip
->wndw_sz_hd_mp
== NULL
);
857 * Check if we have stored a previous message block because a window
858 * update was split over TCP segments. If so, append the new one to
859 * the stored one and process the stored one as if it just arrived.
861 if (rmip
->wndw_sz_hd_mp
!= NULL
) {
862 linkb(rmip
->wndw_sz_hd_mp
, mp
);
863 mp
= rmip
->wndw_sz_hd_mp
;
864 rmip
->wndw_sz_hd_mp
= NULL
;
871 * scan through the entire message block
873 while (tmp
< mp
->b_wptr
) {
875 * check for FF (rlogin magic escape sequence)
877 if (tmp
[0] == RLOGIN_MAGIC
) {
879 * Update bytes read so far.
881 count
= newcount
+ tmp
- mp
->b_rptr
;
883 * Pull together message chain in case
884 * window escape is split across blocks.
886 if ((pullupmsg(newmp
, -1)) == 0) {
887 sz
= msgdsize(newmp
);
888 recover(q
, newmp
, sz
);
892 * pullupmsg results in newmp consuming
893 * all message blocks in this chain, and
894 * therefor mp wants updating.
899 * adjust tmp to where we
900 * stopped - count keeps track
901 * of bytes read so far.
902 * reset newcount = 0.
904 tmp
= mp
->b_rptr
+ count
;
908 * Use the variable tmp1 to compute where
909 * the end of the window escape (currently
910 * the only rlogin protocol sequence), then
911 * check to see if we got all those bytes.
913 tmp1
= tmp
+ 4 + sizeof (struct winsize
);
915 if (tmp1
> mp
->b_wptr
) {
917 * All the window escape bytes aren't
918 * in this TCP segment. Store this
919 * mblk to one side so we can append
920 * the rest of the escape to it when
921 * its segment arrives.
923 rmip
->wndw_sz_hd_mp
= mp
;
927 * check for FF FF s s pattern
929 if ((tmp
[1] == RLOGIN_MAGIC
) &&
930 (tmp
[2] == 's') && (tmp
[3] == 's')) {
933 * If rlwinsetup returns an error,
934 * we do recover with newmp which
935 * points to new chain of mblks after
936 * doing window control ioctls.
937 * rlwinsetup returns newmp which
938 * contains only data part.
939 * Note that buried inside rlwinsetup
940 * is where we do the putnext.
942 if (rlwinsetup(q
, mp
, tmp
) == NULL
) {
948 * We have successfully consumed the
949 * window sequence, but rlwinsetup()
950 * and its children have moved memory
951 * up underneath us. This means that
952 * the byte underneath *tmp has not
953 * been scanned now. We will now need
962 * bump newcount to include size of this particular block.
964 newcount
+= (mp
->b_wptr
- mp
->b_rptr
);
968 * If we trimmed the message down to nothing to forward, don't
969 * send any M_DATA message. (Don't want to send EOF!)
971 if (msgdsize(newmp
) == 0) {
977 if (!canputnext(q
)) {
978 (void) putbq(q
, newmp
);
989 * This routine is called to handle window size changes.
990 * The routine returns 1 on success and 0 on error (allocb failure).
993 rlwinctl(queue_t
*q
, mblk_t
*mp
)
996 struct iocblk
*iocbp
;
997 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
999 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_IN
, "rlwinctl start: q %p, "
1002 rmip
->oobdata
[0] &= ~TIOCPKT_WINDOW
; /* we know they heard */
1004 if ((rl_msgp
= mkiocb(TIOCSWINSZ
)) == NULL
) {
1005 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_OUT
, "rlwinctl end: "
1006 "q %p, mp %p, allocb failed", q
, mp
);
1011 * create an M_IOCTL message type.
1013 rl_msgp
->b_cont
= mp
;
1014 iocbp
= (struct iocblk
*)rl_msgp
->b_rptr
;
1015 iocbp
->ioc_count
= msgdsize(mp
);
1017 putnext(q
, rl_msgp
);
1018 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_OUT
, "rlwinctl end: "
1019 "q %p, mp %p, done", q
, mp
);
1024 * This routine sets up window size change protocol.
1025 * The routine returns the new mblk after issuing rlwinctl
1026 * for window size changes. New mblk contains only data part
1027 * of the message block. The routine returns 0 on error.
1030 rlwinsetup(queue_t
*q
, mblk_t
*mp
, unsigned char *blk
)
1033 unsigned char *jmpmp
;
1038 * Set jmpmp to where to jump, to get just past the end of the
1039 * window size protocol sequence.
1041 jmpmp
= (blk
+ 4 + sizeof (struct winsize
));
1042 left
= mp
->b_wptr
- jmpmp
;
1044 if ((mp1
= allocb(sizeof (struct winsize
), BPRI_MED
)) == NULL
)
1046 mp1
->b_datap
->db_type
= M_DATA
;
1047 mp1
->b_wptr
= mp1
->b_rptr
+ sizeof (struct winsize
);
1048 bcopy(blk
+ 4, &win
, sizeof (struct winsize
));
1049 win
.ws_row
= ntohs(win
.ws_row
);
1050 win
.ws_col
= ntohs(win
.ws_col
);
1051 win
.ws_xpixel
= ntohs(win
.ws_xpixel
);
1052 win
.ws_ypixel
= ntohs(win
.ws_ypixel
);
1053 bcopy(&win
, mp1
->b_rptr
, sizeof (struct winsize
));
1055 if ((rlwinctl(q
, mp1
)) == 0) {
1061 * Must delete the window size protocol sequence. We do
1062 * this by sliding all the stuff after the sequence (jmpmp)
1063 * to where the sequence itself began (blk).
1065 bcopy(jmpmp
, blk
, left
);
1066 mp
->b_wptr
= blk
+ left
;
1073 * When an ioctl changes software flow control on the tty, we must notify
1074 * the rlogin client, so it can adjust its behavior appropriately. This
1075 * routine, called from either the put or service routine, determines if
1076 * the flow handling has changed. If so, it tries to send the indication
1077 * to the client. It returns true or false depending upon whether the
1078 * message was fully processed. If it wasn't fully processed it queues
1079 * the message for retry later when resources
1080 * (allocb/canputnext) are available.
1083 tty_flow(queue_t
*q
, struct rlmod_info
*rmip
, mblk_t
*mp
)
1093 ioc
= (struct iocblk
*)mp
->b_rptr
;
1094 switch (ioc
->ioc_cmd
) {
1097 * If it is a tty ioctl, save the output flow
1098 * control flag and the start and stop flow control
1099 * characters if they are available.
1104 error
= miocpullup(mp
, sizeof (struct termios
));
1106 miocnak(q
, mp
, 0, error
);
1109 tp
= (struct termios
*)(mp
->b_cont
->b_rptr
);
1110 rmip
->stopc
= tp
->c_cc
[VSTOP
];
1111 rmip
->startc
= tp
->c_cc
[VSTART
];
1112 ixon
= tp
->c_iflag
& IXON
;
1118 error
= miocpullup(mp
, sizeof (struct termio
));
1120 miocnak(q
, mp
, 0, error
);
1123 ti
= (struct termio
*)(mp
->b_cont
->b_rptr
);
1124 ixon
= ti
->c_iflag
& IXON
;
1129 * This function must never be called for an M_IOCTL
1130 * except the listed ones.
1134 "rloginmod: tty_flow: bad ioctl 0x%x", ioc
->ioc_cmd
);
1136 miocnak(q
, mp
, 0, EINVAL
);
1141 * If tty ioctl processing is done, check for stopmode
1143 stop
= (ixon
&& (rmip
->stopc
== CTRL('s')) &&
1144 (rmip
->startc
== CTRL('q')));
1145 if (rmip
->stopmode
== TIOCPKT_NOSTOP
) {
1147 cntl
= rmip
->oobdata
[0] | TIOCPKT_DOSTOP
;
1148 if ((tmpmp
= make_expmblk(cntl
)) == NULL
) {
1149 recover(q
, mp
, sizeof (mblk_t
));
1152 if (!canputnext(q
)) {
1157 rmip
->stopmode
= TIOCPKT_DOSTOP
;
1161 cntl
= rmip
->oobdata
[0] | TIOCPKT_NOSTOP
;
1162 if ((tmpmp
= make_expmblk(cntl
)) == NULL
) {
1163 recover(q
, mp
, sizeof (mblk_t
));
1166 if (!canputnext(q
)) {
1171 rmip
->stopmode
= TIOCPKT_NOSTOP
;
1175 miocack(q
, mp
, 0, 0);
1179 /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
1182 rlmodwioctl(queue_t
*q
, mblk_t
*mp
)
1185 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1188 ioc
= (struct iocblk
*)mp
->b_rptr
;
1189 switch (ioc
->ioc_cmd
) {
1192 * This is a special ioctl to reenable the queue.
1193 * The initial data read from the stream head is
1194 * put back on the queue.
1198 * Send negative ack if RL_DISABLED flag is not set
1201 if (!(rmip
->flags
& RL_DISABLED
)) {
1202 miocnak(q
, mp
, 0, EINVAL
);
1206 (void) putbq(RD(q
), mp
->b_cont
);
1210 if (rmip
->flags
& RL_DISABLED
)
1211 rmip
->flags
&= ~RL_DISABLED
;
1213 miocack(q
, mp
, 0, 0);
1214 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
1215 "rlmodwput end: q %p, mp %p, %s",
1216 q
, mp
, "IOCACK enable");
1220 * If it is a tty ioctl, save the output flow
1221 * control flag and the start and stop flow control
1222 * characters if they are available.
1230 return (tty_flow(q
, rmip
, mp
));
1236 miocnak(q
, mp
, 0, EINVAL
);
1240 error
= miocpullup(mp
, sizeof (uchar_t
));
1242 miocnak(q
, mp
, 0, error
);
1245 if (*(mp
->b_cont
->b_rptr
) == 0x01)
1246 rmip
->flags
|= RL_IOCPASSTHRU
;
1248 rmip
->flags
&= ~RL_IOCPASSTHRU
;
1250 miocack(q
, mp
, 0, 0);
1254 if (rmip
->flags
& RL_IOCPASSTHRU
) {
1259 "rlmodwioctl: unexpected ioctl type 0x%x",
1262 miocnak(q
, mp
, 0, EINVAL
);
1269 rlmod_timer(void *arg
)
1272 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1275 if (q
->q_flag
& QREADR
) {
1276 ASSERT(rmip
->rtimoutid
);
1277 rmip
->rtimoutid
= 0;
1279 ASSERT(rmip
->wtimoutid
);
1280 rmip
->wtimoutid
= 0;
1287 rlmod_buffer(void *arg
)
1290 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1293 if (q
->q_flag
& QREADR
) {
1294 ASSERT(rmip
->rbufcid
);
1297 ASSERT(rmip
->wbufcid
);
1305 recover(queue_t
*q
, mblk_t
*mp
, size_t size
)
1308 * Avoid re-enabling the queue.
1310 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
1313 (void) putbq(q
, mp
);
1318 recover1(queue_t
*q
, size_t size
)
1320 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1325 * Make sure there is at most one outstanding request per queue.
1327 if (q
->q_flag
& QREADR
) {
1328 if (rmip
->rtimoutid
|| rmip
->rbufcid
)
1331 if (rmip
->wtimoutid
|| rmip
->wbufcid
)
1334 if (!(bid
= qbufcall(RD(q
), size
, BPRI_MED
, rlmod_buffer
, q
))) {
1335 tid
= qtimeout(RD(q
), rlmod_timer
, q
, SIMWAIT
);
1336 if (q
->q_flag
& QREADR
)
1337 rmip
->rtimoutid
= tid
;
1339 rmip
->wtimoutid
= tid
;
1341 if (q
->q_flag
& QREADR
)
1342 rmip
->rbufcid
= bid
;
1344 rmip
->wbufcid
= bid
;