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.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This module implements the services provided by the rlogin daemon
31 * after the connection is set up. Mainly this means responding to
32 * interrupts and window size changes. It begins operation in "disabled"
33 * state, and sends a T_DATA_REQ to the daemon to indicate that it is
34 * in place and ready to be enabled. The daemon can then know when all
35 * data which sneaked passed rlmod (before it was pushed) has been received.
36 * The daemon may process this data, or send data back to be inserted in
37 * the read queue at the head with the RL_IOC_ENABLE ioctl.
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>
46 #include <sys/errno.h>
48 #include <sys/sunddi.h>
49 #include <sys/tihdr.h>
52 #include <sys/debug.h>
53 #include <sys/modctl.h>
54 #include <sys/vtrace.h>
55 #include <sys/rlioctl.h>
56 #include <sys/termios.h>
57 #include <sys/termio.h>
58 #include <sys/byteorder.h>
59 #include <sys/cmn_err.h>
60 #include <sys/cryptmod.h>
62 extern struct streamtab rloginmodinfo
;
64 static struct fmodsw fsw
= {
71 * Module linkage information for the kernel.
74 static struct modlstrmod modlstrmod
= {
80 static struct modlinkage modlinkage
= {
81 MODREV_1
, &modlstrmod
, NULL
88 return (mod_install(&modlinkage
));
94 return (mod_remove(&modlinkage
));
98 _info(struct modinfo
*modinfop
)
100 return (mod_info(&modlinkage
, modinfop
));
103 struct rlmod_info
; /* forward reference for function prototype */
105 static int rlmodopen(queue_t
*, dev_t
*, int, int, cred_t
*);
106 static int rlmodclose(queue_t
*, int, cred_t
*);
107 static int rlmodrput(queue_t
*, mblk_t
*);
108 static int rlmodrsrv(queue_t
*);
109 static int rlmodwput(queue_t
*, mblk_t
*);
110 static int rlmodwsrv(queue_t
*);
111 static int rlmodrmsg(queue_t
*, mblk_t
*);
112 static mblk_t
*make_expmblk(char);
113 static int rlwinctl(queue_t
*, mblk_t
*);
114 static mblk_t
*rlwinsetup(queue_t
*, mblk_t
*, unsigned char *);
116 static void rlmod_timer(void *);
117 static void rlmod_buffer(void *);
118 static boolean_t
tty_flow(queue_t
*, struct rlmod_info
*, mblk_t
*);
119 static boolean_t
rlmodwioctl(queue_t
*, mblk_t
*);
120 static void recover(queue_t
*, mblk_t
*, size_t);
121 static void recover1(queue_t
*, size_t);
124 #define SIMWAIT (1*hz)
127 * Stream module data structure definitions.
128 * generally pushed onto tcp by rlogin daemon
131 static struct module_info rloginmodiinfo
= {
132 RLMOD_ID
, /* module id number */
133 "rlmod", /* module name */
134 0, /* minimum packet size */
135 INFPSZ
, /* maximum packet size */
136 512, /* hi-water mark */
137 256 /* lo-water mark */
140 static struct qinit rloginmodrinit
= {
150 static struct qinit rloginmodwinit
= {
160 struct streamtab rloginmodinfo
= {
168 * Per-instance state struct for the rloginmod module.
173 bufcall_id_t wbufcid
;
174 bufcall_id_t rbufcid
;
175 timeout_id_t wtimoutid
;
176 timeout_id_t rtimoutid
;
183 mblk_t
*wndw_sz_hd_mp
;
189 #define RL_DISABLED 0x1
190 #define RL_IOCPASSTHRU 0x2
194 dummy_callback(void *arg
)
198 * rlmodopen - open routine gets called when the
199 * module gets pushed onto the stream.
203 rlmodopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*cred
)
205 struct rlmod_info
*rmip
;
206 union T_primitives
*tp
;
210 if (sflag
!= MODOPEN
)
213 if (q
->q_ptr
!= NULL
) {
214 /* It's already attached. */
219 * Allocate state structure.
221 rmip
= kmem_zalloc(sizeof (*rmip
), KM_SLEEP
);
229 rmip
->stopmode
= TIOCPKT_DOSTOP
;
230 rmip
->startc
= CTRL('q');
231 rmip
->stopc
= CTRL('s');
232 rmip
->oobdata
[0] = (char)TIOCPKT_WINDOW
;
233 rmip
->wndw_sz_hd_mp
= NULL
;
235 * Allow only non-M_DATA blocks to pass up to in.rlogind until
236 * it is ready for M_DATA (indicated by RL_IOC_ENABLE).
238 rmip
->flags
|= RL_DISABLED
;
243 * Since TCP operates in the TLI-inspired brain-dead fashion,
244 * the connection will revert to bound state if the connection
245 * is reset by the client. We must send a T_UNBIND_REQ in
246 * that case so the port doesn't get "wedged" (preventing
247 * inetd from being able to restart the listener). Allocate
248 * it here, so that we don't need to worry about allocb()
251 while ((rmip
->unbind_mp
= allocb(sizeof (union T_primitives
),
253 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
254 BPRI_HI
, dummy_callback
, NULL
);
262 rmip
->unbind_mp
->b_wptr
= rmip
->unbind_mp
->b_rptr
+
263 sizeof (struct T_unbind_req
);
264 rmip
->unbind_mp
->b_datap
->db_type
= M_PROTO
;
265 tp
= (union T_primitives
*)rmip
->unbind_mp
->b_rptr
;
266 tp
->type
= T_UNBIND_REQ
;
269 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
270 * read queue since only write queue can get T_DATA_REQ).
271 * Readstream routine in the daemon will do a getmsg() till
272 * it receives this proto message.
274 while ((bp
= allocb(sizeof (union T_primitives
), BPRI_HI
)) == NULL
) {
275 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
276 BPRI_HI
, dummy_callback
, NULL
);
284 bp
->b_datap
->db_type
= M_PROTO
;
285 bp
->b_wptr
= bp
->b_rptr
+ sizeof (union T_primitives
);
286 tp
= (union T_primitives
*)bp
->b_rptr
;
287 tp
->type
= T_DATA_REQ
;
288 tp
->data_req
.MORE_flag
= 0;
294 if (rmip
->unbind_mp
!= NULL
) {
295 freemsg(rmip
->unbind_mp
);
297 kmem_free(rmip
, sizeof (struct rlmod_info
));
305 * rlmodclose - This routine gets called when the module
306 * gets popped off of the stream.
311 rlmodclose(queue_t
*q
, int flag
, cred_t
*credp
)
313 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
317 * Flush any write-side data downstream. Ignoring flow
318 * control at this point is known to be safe because the
319 * M_HANGUP below poisons the stream such that no modules can
322 while (mp
= getq(WR(q
)))
325 /* Poison the stream head so that we can't be pushed again. */
326 (void) putnextctl(q
, M_HANGUP
);
330 qunbufcall(q
, rmip
->wbufcid
);
334 qunbufcall(q
, rmip
->rbufcid
);
337 if (rmip
->wtimoutid
) {
338 (void) quntimeout(q
, rmip
->wtimoutid
);
341 if (rmip
->rtimoutid
) {
342 (void) quntimeout(q
, rmip
->rtimoutid
);
346 if (rmip
->unbind_mp
!= NULL
) {
347 freemsg(rmip
->unbind_mp
);
350 if (rmip
->wndw_sz_hd_mp
!= NULL
) {
351 freemsg(rmip
->wndw_sz_hd_mp
);
354 kmem_free(q
->q_ptr
, sizeof (struct rlmod_info
));
355 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
360 * rlmodrput - Module read queue put procedure.
361 * This is called from the module or
366 rlmodrput(queue_t
*q
, mblk_t
*mp
)
368 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
369 union T_primitives
*tip
;
371 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_IN
, "rlmodrput start: "
372 "q %p, mp %p", q
, mp
);
375 /* if low (normal) priority... */
376 if ((mp
->b_datap
->db_type
< QPCTL
) &&
377 /* ...and data is already queued... */
379 /* ...or currently disabled and this is M_DATA... */
380 ((rmip
->flags
& RL_DISABLED
) &&
381 (mp
->b_datap
->db_type
== M_DATA
)))) {
382 /* ...delay delivery of the message */
384 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_OUT
,
385 "rlmodrput end: q %p, mp %p, %s", q
, mp
, "flow");
389 switch (mp
->b_datap
->db_type
) {
393 tip
= (union T_primitives
*)mp
->b_rptr
;
398 /* Make into M_HANGUP and putnext */
399 mp
->b_datap
->db_type
= M_HANGUP
;
400 mp
->b_wptr
= mp
->b_rptr
;
406 * If we haven't already, send T_UNBIND_REQ to prevent
407 * TCP from going into "BOUND" state and locking up the
410 if (tip
->type
== T_DISCON_IND
&& rmip
->unbind_mp
!=
413 qreply(q
, rmip
->unbind_mp
);
414 rmip
->unbind_mp
= NULL
;
421 * We only get T_OK_ACK when we issue the unbind, and it can
425 ASSERT(rmip
->unbind_mp
== NULL
);
431 "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
438 if (canputnext(q
) && q
->q_first
== NULL
) {
439 (void) rlmodrmsg(q
, mp
);
447 * Since M_FLUSH came from TCP, we mark it bound for
448 * daemon, not tty. This only happens when TCP expects
449 * to do a connection reset.
451 mp
->b_flag
|= MSGMARK
;
452 if (*mp
->b_rptr
& FLUSHR
)
463 if (mp
->b_datap
->db_type
<= QPCTL
&& !canputnext(q
))
471 cmn_err(CE_NOTE
, "rlmodrput: unexpected msg type 0x%x",
472 mp
->b_datap
->db_type
);
476 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RPUT_OUT
, "rlmodrput end: q %p, "
477 "mp %p, %s", q
, mp
, "done");
482 * rlmodrsrv - module read service procedure
485 rlmodrsrv(queue_t
*q
)
488 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
489 union T_primitives
*tip
;
491 TRACE_1(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_IN
, "rlmodrsrv start: "
493 while ((mp
= getq(q
)) != NULL
) {
495 switch (mp
->b_datap
->db_type
) {
497 if (rmip
->flags
& RL_DISABLED
) {
499 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
500 "rlmodrsrv end: q %p, mp %p, %s", q
, mp
,
504 if (!canputnext(q
)) {
506 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
507 "rlmodrsrv end: q %p, mp %p, %s",
508 q
, mp
, "!canputnext");
511 if (!rlmodrmsg(q
, mp
)) {
512 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
513 "rlmodrsrv end: q %p, mp %p, %s",
514 q
, mp
, "!rlmodrmsg");
520 tip
= (union T_primitives
*)mp
->b_rptr
;
525 /* Make into M_HANGUP and putnext */
526 mp
->b_datap
->db_type
= M_HANGUP
;
527 mp
->b_wptr
= mp
->b_rptr
;
533 * If we haven't already, send T_UNBIND_REQ
534 * to prevent TCP from going into "BOUND"
535 * state and locking up the port.
537 if (tip
->type
== T_DISCON_IND
&&
538 rmip
->unbind_mp
!= NULL
) {
540 qreply(q
, rmip
->unbind_mp
);
541 rmip
->unbind_mp
= NULL
;
548 * We only get T_OK_ACK when we issue the unbind, and
549 * it can be ignored safely.
552 ASSERT(rmip
->unbind_mp
== NULL
);
558 "rlmodrsrv: got 0x%x type PROTO msg",
565 if (!canputnext(q
)) {
567 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
,
568 "rlmodrsrv end: q %p, mp %p, %s",
569 q
, mp
, "!canputnext M_SETOPTS");
578 "rlmodrsrv: unexpected msg type 0x%x",
579 mp
->b_datap
->db_type
);
585 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_RSRV_OUT
, "rlmodrsrv end: q %p, "
586 "mp %p, %s", q
, mp
, "empty");
592 * rlmodwput - Module write queue put procedure.
593 * All non-zero messages are send downstream unchanged
596 rlmodwput(queue_t
*q
, mblk_t
*mp
)
599 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
603 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_IN
, "rlmodwput start: "
604 "q %p, mp %p", q
, mp
);
606 if (rmip
->rl_expdat
) {
608 * call make_expmblk to create an expedited
611 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
613 if (!canputnext(q
)) {
615 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
616 "rlmodwput end: q %p, mp %p, %s",
617 q
, mp
, "expdata && !canputnext");
620 if ((tmpmp
= make_expmblk(cntl
))) {
624 recover1(q
, sizeof (mblk_t
)); /* XXX.sparker */
628 if ((q
->q_first
|| rmip
->rl_expdat
) && mp
->b_datap
->db_type
< QPCTL
) {
630 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
, "rlmodwput end: "
631 "q %p, mp %p, %s", q
, mp
, "queued data");
634 switch (mp
->b_datap
->db_type
) {
645 * We must take care to create and forward out-of-band data
646 * indicating the flush to the far side.
649 *mp
->b_rptr
&= ~FLUSHW
;
653 * Since all rlogin protocol data is sent in this
654 * direction as urgent data, and TCP does not flush
655 * urgent data, it is okay to actually forward this
656 * flush. (telmod cannot.)
658 flushq(q
, FLUSHDATA
);
660 * The putnextctl1() call can only fail if we're
661 * out of memory. Ideally, we might set a state
662 * bit and reschedule ourselves when memory
663 * becomes available, so we make sure not to miss
664 * sending the FLUSHW to TCP before the urgent
665 * byte. Not doing this just means in some cases
666 * a bit more trash passes before the flush takes
669 (void) putnextctl1(q
, M_FLUSH
, FLUSHW
);
671 * Notify peer of the write flush request.
673 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
674 if (!canputnext(q
)) {
675 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
676 "rlmodwput end: q %p, mp %p, %s",
677 q
, mp
, "flushw && !canputnext");
680 if ((mp
= make_expmblk(cntl
)) == NULL
) {
682 recover1(q
, sizeof (mblk_t
));
683 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
684 "rlmodwput end: q %p, mp %p, %s",
685 q
, mp
, "!make_expmblk");
693 if (!rlmodwioctl(q
, mp
))
698 switch (((union T_primitives
*)mp
->b_rptr
)->type
) {
708 "rlmodwput: unexpected TPI primitive 0x%x",
709 ((union T_primitives
*)mp
->b_rptr
)->type
);
716 if (((struct T_exdata_req
*)mp
->b_rptr
)->PRIM_type
==
720 /* XXX.sparker Log unexpected message */
728 "rlmodwput: unexpected msg type 0x%x",
729 mp
->b_datap
->db_type
);
734 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
, "rlmodwput end: "
735 "q %p, mp %p, %s", q
, mp
, "done");
740 * rlmodwsrv - module write service procedure
743 rlmodwsrv(queue_t
*q
)
747 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
749 TRACE_1(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_IN
, "rlmodwsrv "
751 if (rmip
->rl_expdat
) {
753 * call make_expmblk to create an expedited
756 cntl
= rmip
->oobdata
[0] | TIOCPKT_FLUSHWRITE
;
757 if (!canputnext(q
)) {
758 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
759 "rlmodwsrv end: q %p, mp %p, %s",
760 q
, NULL
, "!canputnext && expdat");
763 if ((tmpmp
= make_expmblk(cntl
))) {
767 recover1(q
, sizeof (mblk_t
));
768 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
769 "rlmodwsrv end: q %p, mp %p, %s",
770 q
, NULL
, "!make_expmblk");
774 while ((mp
= getq(q
)) != NULL
) {
776 if (!canputnext(q
) || rmip
->rl_expdat
) {
778 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
779 "rlmodwsrv end: q %p, mp %p, %s",
780 q
, mp
, "!canputnext || expdat");
783 if (mp
->b_datap
->db_type
== M_IOCTL
) {
784 if (!rlmodwioctl(q
, mp
)) {
785 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
,
786 "rlmodwsrv end: q %p, mp %p, %s",
787 q
, mp
, "!rlmodwioctl");
795 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WSRV_OUT
, "rlmodwsrv end: q %p, "
796 "mp %p, %s", q
, mp
, "done");
801 * This routine returns a message block with an expedited
805 make_expmblk(char cntl
)
809 struct T_exdata_req
*data_req
;
811 bp
= allocb(sizeof (struct T_exdata_req
), BPRI_MED
);
814 if ((mp
= allocb(sizeof (char), BPRI_MED
)) == NULL
) {
818 bp
->b_datap
->db_type
= M_PROTO
;
819 data_req
= (struct T_exdata_req
*)bp
->b_rptr
;
820 data_req
->PRIM_type
= T_EXDATA_REQ
;
821 data_req
->MORE_flag
= 0;
823 bp
->b_wptr
+= sizeof (struct T_exdata_req
);
825 * Send a 1 byte data message block with appropriate
828 mp
->b_datap
->db_type
= M_DATA
;
829 mp
->b_wptr
= mp
->b_rptr
+ 1;
830 (*(char *)(mp
->b_rptr
)) = cntl
;
835 * This routine parses M_DATA messages checking for window size protocol
836 * from a given message block. It returns TRUE if no resource exhaustion
837 * conditions are found. This is for use in the service procedure, which
838 * needs to know whether to continue, or stop processing the queue.
841 rlmodrmsg(queue_t
*q
, mblk_t
*mp
)
843 unsigned char *tmp
, *tmp1
;
846 ssize_t count
, newcount
= 0;
847 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
850 * Eliminate any zero length messages here, so we don't filter EOFs
853 if (msgdsize(mp
) == 0) {
854 ASSERT(rmip
->wndw_sz_hd_mp
== NULL
);
858 * Check if we have stored a previous message block because a window
859 * update was split over TCP segments. If so, append the new one to
860 * the stored one and process the stored one as if it just arrived.
862 if (rmip
->wndw_sz_hd_mp
!= NULL
) {
863 linkb(rmip
->wndw_sz_hd_mp
, mp
);
864 mp
= rmip
->wndw_sz_hd_mp
;
865 rmip
->wndw_sz_hd_mp
= NULL
;
872 * scan through the entire message block
874 while (tmp
< mp
->b_wptr
) {
876 * check for FF (rlogin magic escape sequence)
878 if (tmp
[0] == RLOGIN_MAGIC
) {
880 * Update bytes read so far.
882 count
= newcount
+ tmp
- mp
->b_rptr
;
884 * Pull together message chain in case
885 * window escape is split across blocks.
887 if ((pullupmsg(newmp
, -1)) == 0) {
888 sz
= msgdsize(newmp
);
889 recover(q
, newmp
, sz
);
893 * pullupmsg results in newmp consuming
894 * all message blocks in this chain, and
895 * therefor mp wants updating.
900 * adjust tmp to where we
901 * stopped - count keeps track
902 * of bytes read so far.
903 * reset newcount = 0.
905 tmp
= mp
->b_rptr
+ count
;
909 * Use the variable tmp1 to compute where
910 * the end of the window escape (currently
911 * the only rlogin protocol sequence), then
912 * check to see if we got all those bytes.
914 tmp1
= tmp
+ 4 + sizeof (struct winsize
);
916 if (tmp1
> mp
->b_wptr
) {
918 * All the window escape bytes aren't
919 * in this TCP segment. Store this
920 * mblk to one side so we can append
921 * the rest of the escape to it when
922 * its segment arrives.
924 rmip
->wndw_sz_hd_mp
= mp
;
928 * check for FF FF s s pattern
930 if ((tmp
[1] == RLOGIN_MAGIC
) &&
931 (tmp
[2] == 's') && (tmp
[3] == 's')) {
934 * If rlwinsetup returns an error,
935 * we do recover with newmp which
936 * points to new chain of mblks after
937 * doing window control ioctls.
938 * rlwinsetup returns newmp which
939 * contains only data part.
940 * Note that buried inside rlwinsetup
941 * is where we do the putnext.
943 if (rlwinsetup(q
, mp
, tmp
) == NULL
) {
949 * We have successfully consumed the
950 * window sequence, but rlwinsetup()
951 * and its children have moved memory
952 * up underneath us. This means that
953 * the byte underneath *tmp has not
954 * been scanned now. We will now need
963 * bump newcount to include size of this particular block.
965 newcount
+= (mp
->b_wptr
- mp
->b_rptr
);
969 * If we trimmed the message down to nothing to forward, don't
970 * send any M_DATA message. (Don't want to send EOF!)
972 if (msgdsize(newmp
) == 0) {
978 if (!canputnext(q
)) {
979 (void) putbq(q
, newmp
);
990 * This routine is called to handle window size changes.
991 * The routine returns 1 on success and 0 on error (allocb failure).
994 rlwinctl(queue_t
*q
, mblk_t
*mp
)
997 struct iocblk
*iocbp
;
998 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1000 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_IN
, "rlwinctl start: q %p, "
1003 rmip
->oobdata
[0] &= ~TIOCPKT_WINDOW
; /* we know he heard */
1005 if ((rl_msgp
= mkiocb(TIOCSWINSZ
)) == NULL
) {
1006 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_OUT
, "rlwinctl end: "
1007 "q %p, mp %p, allocb failed", q
, mp
);
1012 * create an M_IOCTL message type.
1014 rl_msgp
->b_cont
= mp
;
1015 iocbp
= (struct iocblk
*)rl_msgp
->b_rptr
;
1016 iocbp
->ioc_count
= msgdsize(mp
);
1018 putnext(q
, rl_msgp
);
1019 TRACE_2(TR_FAC_RLOGINP
, TR_RLOGINP_WINCTL_OUT
, "rlwinctl end: "
1020 "q %p, mp %p, done", q
, mp
);
1025 * This routine sets up window size change protocol.
1026 * The routine returns the new mblk after issuing rlwinctl
1027 * for window size changes. New mblk contains only data part
1028 * of the message block. The routine returns 0 on error.
1031 rlwinsetup(queue_t
*q
, mblk_t
*mp
, unsigned char *blk
)
1034 unsigned char *jmpmp
;
1039 * Set jmpmp to where to jump, to get just past the end of the
1040 * window size protocol sequence.
1042 jmpmp
= (blk
+ 4 + sizeof (struct winsize
));
1043 left
= mp
->b_wptr
- jmpmp
;
1045 if ((mp1
= allocb(sizeof (struct winsize
), BPRI_MED
)) == NULL
)
1047 mp1
->b_datap
->db_type
= M_DATA
;
1048 mp1
->b_wptr
= mp1
->b_rptr
+ sizeof (struct winsize
);
1049 bcopy(blk
+ 4, &win
, sizeof (struct winsize
));
1050 win
.ws_row
= ntohs(win
.ws_row
);
1051 win
.ws_col
= ntohs(win
.ws_col
);
1052 win
.ws_xpixel
= ntohs(win
.ws_xpixel
);
1053 win
.ws_ypixel
= ntohs(win
.ws_ypixel
);
1054 bcopy(&win
, mp1
->b_rptr
, sizeof (struct winsize
));
1056 if ((rlwinctl(q
, mp1
)) == NULL
) {
1062 * Must delete the window size protocol sequence. We do
1063 * this by sliding all the stuff after the sequence (jmpmp)
1064 * to where the sequence itself began (blk).
1066 bcopy(jmpmp
, blk
, left
);
1067 mp
->b_wptr
= blk
+ left
;
1074 * When an ioctl changes software flow control on the tty, we must notify
1075 * the rlogin client, so it can adjust its behavior appropriately. This
1076 * routine, called from either the put or service routine, determines if
1077 * the flow handling has changed. If so, it tries to send the indication
1078 * to the client. It returns true or false depending upon whether the
1079 * message was fully processed. If it wasn't fully processed it queues
1080 * the message for retry later when resources
1081 * (allocb/canputnext) are available.
1084 tty_flow(queue_t
*q
, struct rlmod_info
*rmip
, mblk_t
*mp
)
1094 ioc
= (struct iocblk
*)mp
->b_rptr
;
1095 switch (ioc
->ioc_cmd
) {
1098 * If it is a tty ioctl, save the output flow
1099 * control flag and the start and stop flow control
1100 * characters if they are available.
1105 error
= miocpullup(mp
, sizeof (struct termios
));
1107 miocnak(q
, mp
, 0, error
);
1110 tp
= (struct termios
*)(mp
->b_cont
->b_rptr
);
1111 rmip
->stopc
= tp
->c_cc
[VSTOP
];
1112 rmip
->startc
= tp
->c_cc
[VSTART
];
1113 ixon
= tp
->c_iflag
& IXON
;
1119 error
= miocpullup(mp
, sizeof (struct termio
));
1121 miocnak(q
, mp
, 0, error
);
1124 ti
= (struct termio
*)(mp
->b_cont
->b_rptr
);
1125 ixon
= ti
->c_iflag
& IXON
;
1130 * This function must never be called for an M_IOCTL
1131 * except the listed ones.
1135 "rloginmod: tty_flow: bad ioctl 0x%x", ioc
->ioc_cmd
);
1137 miocnak(q
, mp
, 0, EINVAL
);
1142 * If tty ioctl processing is done, check for stopmode
1144 stop
= (ixon
&& (rmip
->stopc
== CTRL('s')) &&
1145 (rmip
->startc
== CTRL('q')));
1146 if (rmip
->stopmode
== TIOCPKT_NOSTOP
) {
1148 cntl
= rmip
->oobdata
[0] | TIOCPKT_DOSTOP
;
1149 if ((tmpmp
= make_expmblk(cntl
)) == NULL
) {
1150 recover(q
, mp
, sizeof (mblk_t
));
1153 if (!canputnext(q
)) {
1158 rmip
->stopmode
= TIOCPKT_DOSTOP
;
1162 cntl
= rmip
->oobdata
[0] | TIOCPKT_NOSTOP
;
1163 if ((tmpmp
= make_expmblk(cntl
)) == NULL
) {
1164 recover(q
, mp
, sizeof (mblk_t
));
1167 if (!canputnext(q
)) {
1172 rmip
->stopmode
= TIOCPKT_NOSTOP
;
1176 miocack(q
, mp
, 0, 0);
1180 /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
1183 rlmodwioctl(queue_t
*q
, mblk_t
*mp
)
1186 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1189 ioc
= (struct iocblk
*)mp
->b_rptr
;
1190 switch (ioc
->ioc_cmd
) {
1193 * This is a special ioctl to reenable the queue.
1194 * The initial data read from the stream head is
1195 * put back on the queue.
1199 * Send negative ack if RL_DISABLED flag is not set
1202 if (!(rmip
->flags
& RL_DISABLED
)) {
1203 miocnak(q
, mp
, 0, EINVAL
);
1207 (void) putbq(RD(q
), mp
->b_cont
);
1211 if (rmip
->flags
& RL_DISABLED
)
1212 rmip
->flags
&= ~RL_DISABLED
;
1214 miocack(q
, mp
, 0, 0);
1215 TRACE_3(TR_FAC_RLOGINP
, TR_RLOGINP_WPUT_OUT
,
1216 "rlmodwput end: q %p, mp %p, %s",
1217 q
, mp
, "IOCACK enable");
1221 * If it is a tty ioctl, save the output flow
1222 * control flag and the start and stop flow control
1223 * characters if they are available.
1231 return (tty_flow(q
, rmip
, mp
));
1237 miocnak(q
, mp
, 0, EINVAL
);
1241 error
= miocpullup(mp
, sizeof (uchar_t
));
1243 miocnak(q
, mp
, 0, error
);
1246 if (*(mp
->b_cont
->b_rptr
) == 0x01)
1247 rmip
->flags
|= RL_IOCPASSTHRU
;
1249 rmip
->flags
&= ~RL_IOCPASSTHRU
;
1251 miocack(q
, mp
, NULL
, 0);
1255 if (rmip
->flags
& RL_IOCPASSTHRU
) {
1260 "rlmodwioctl: unexpected ioctl type 0x%x",
1263 miocnak(q
, mp
, 0, EINVAL
);
1270 rlmod_timer(void *arg
)
1273 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1276 if (q
->q_flag
& QREADR
) {
1277 ASSERT(rmip
->rtimoutid
);
1278 rmip
->rtimoutid
= 0;
1280 ASSERT(rmip
->wtimoutid
);
1281 rmip
->wtimoutid
= 0;
1288 rlmod_buffer(void *arg
)
1291 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1294 if (q
->q_flag
& QREADR
) {
1295 ASSERT(rmip
->rbufcid
);
1298 ASSERT(rmip
->wbufcid
);
1306 recover(queue_t
*q
, mblk_t
*mp
, size_t size
)
1309 * Avoid re-enabling the queue.
1311 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
1314 (void) putbq(q
, mp
);
1319 recover1(queue_t
*q
, size_t size
)
1321 struct rlmod_info
*rmip
= (struct rlmod_info
*)q
->q_ptr
;
1326 * Make sure there is at most one outstanding request per queue.
1328 if (q
->q_flag
& QREADR
) {
1329 if (rmip
->rtimoutid
|| rmip
->rbufcid
)
1332 if (rmip
->wtimoutid
|| rmip
->wbufcid
)
1335 if (!(bid
= qbufcall(RD(q
), size
, BPRI_MED
, rlmod_buffer
, q
))) {
1336 tid
= qtimeout(RD(q
), rlmod_timer
, q
, SIMWAIT
);
1337 if (q
->q_flag
& QREADR
)
1338 rmip
->rtimoutid
= tid
;
1340 rmip
->wtimoutid
= tid
;
1342 if (q
->q_flag
& QREADR
)
1343 rmip
->rbufcid
= bid
;
1345 rmip
->wbufcid
= bid
;