6324 Add an `ndp' tool for manipulating the neighbors table
[illumos-gate.git] / usr / src / uts / common / io / rlmod.c
bloba3b9a50a74f78a07ba679250e16dda2012765639
1 /*
2 * CDDL HEADER START
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.
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]
20 * CDDL HEADER END
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>
45 #include <sys/kmem.h>
46 #include <sys/errno.h>
47 #include <sys/ddi.h>
48 #include <sys/sunddi.h>
49 #include <sys/tihdr.h>
50 #include <sys/ptem.h>
51 #include <sys/conf.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 = {
65 "rlmod",
66 &rloginmodinfo,
67 D_MTQPAIR | D_MP
71 * Module linkage information for the kernel.
74 static struct modlstrmod modlstrmod = {
75 &mod_strmodops,
76 "rloginmod module",
77 &fsw
80 static struct modlinkage modlinkage = {
81 MODREV_1, &modlstrmod, NULL
85 int
86 _init(void)
88 return (mod_install(&modlinkage));
91 int
92 _fini(void)
94 return (mod_remove(&modlinkage));
97 int
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);
123 #define RLMOD_ID 106
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 = {
141 rlmodrput,
142 rlmodrsrv,
143 rlmodopen,
144 rlmodclose,
145 nulldev,
146 &rloginmodiinfo,
147 NULL
150 static struct qinit rloginmodwinit = {
151 rlmodwput,
152 rlmodwsrv,
153 NULL,
154 NULL,
155 nulldev,
156 &rloginmodiinfo,
157 NULL
160 struct streamtab rloginmodinfo = {
161 &rloginmodrinit,
162 &rloginmodwinit,
163 NULL,
164 NULL
168 * Per-instance state struct for the rloginmod module.
170 struct rlmod_info
172 int flags;
173 bufcall_id_t wbufcid;
174 bufcall_id_t rbufcid;
175 timeout_id_t wtimoutid;
176 timeout_id_t rtimoutid;
177 int rl_expdat;
178 int stopmode;
179 mblk_t *unbind_mp;
180 char startc;
181 char stopc;
182 char oobdata[1];
183 mblk_t *wndw_sz_hd_mp;
187 * Flag used in flags
189 #define RL_DISABLED 0x1
190 #define RL_IOCPASSTHRU 0x2
192 /*ARGSUSED*/
193 static void
194 dummy_callback(void *arg)
198 * rlmodopen - open routine gets called when the
199 * module gets pushed onto the stream.
201 /*ARGSUSED*/
202 static int
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;
207 mblk_t *bp;
208 int error;
210 if (sflag != MODOPEN)
211 return (EINVAL);
213 if (q->q_ptr != NULL) {
214 /* It's already attached. */
215 return (0);
219 * Allocate state structure.
221 rmip = kmem_zalloc(sizeof (*rmip), KM_SLEEP);
224 * Cross-link.
226 q->q_ptr = rmip;
227 WR(q)->q_ptr = rmip;
228 rmip->rl_expdat = 0;
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;
240 qprocson(q);
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()
249 * failures later.
251 while ((rmip->unbind_mp = allocb(sizeof (union T_primitives),
252 BPRI_HI)) == NULL) {
253 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
254 BPRI_HI, dummy_callback, NULL);
255 if (!qwait_sig(q)) {
256 qunbufcall(q, id);
257 error = EINTR;
258 goto fail;
260 qunbufcall(q, id);
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);
277 if (!qwait_sig(q)) {
278 qunbufcall(q, id);
279 error = EINTR;
280 goto fail;
282 qunbufcall(q, id);
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;
290 putnext(q, bp);
291 return (0);
292 fail:
293 qprocsoff(q);
294 if (rmip->unbind_mp != NULL) {
295 freemsg(rmip->unbind_mp);
297 kmem_free(rmip, sizeof (struct rlmod_info));
298 q->q_ptr = NULL;
299 WR(q)->q_ptr = NULL;
300 return (error);
305 * rlmodclose - This routine gets called when the module
306 * gets popped off of the stream.
309 /*ARGSUSED*/
310 static int
311 rlmodclose(queue_t *q, int flag, cred_t *credp)
313 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
314 mblk_t *mp;
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
320 * be pushed again.
322 while (mp = getq(WR(q)))
323 putnext(WR(q), mp);
325 /* Poison the stream head so that we can't be pushed again. */
326 (void) putnextctl(q, M_HANGUP);
328 qprocsoff(q);
329 if (rmip->wbufcid) {
330 qunbufcall(q, rmip->wbufcid);
331 rmip->wbufcid = 0;
333 if (rmip->rbufcid) {
334 qunbufcall(q, rmip->rbufcid);
335 rmip->rbufcid = 0;
337 if (rmip->wtimoutid) {
338 (void) quntimeout(q, rmip->wtimoutid);
339 rmip->wtimoutid = 0;
341 if (rmip->rtimoutid) {
342 (void) quntimeout(q, rmip->rtimoutid);
343 rmip->rtimoutid = 0;
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;
356 return (0);
360 * rlmodrput - Module read queue put procedure.
361 * This is called from the module or
362 * driver downstream.
365 static int
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... */
378 ((q->q_first) ||
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 */
383 (void) putq(q, mp);
384 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT,
385 "rlmodrput end: q %p, mp %p, %s", q, mp, "flow");
386 return (0);
389 switch (mp->b_datap->db_type) {
391 case M_PROTO:
392 case M_PCPROTO:
393 tip = (union T_primitives *)mp->b_rptr;
394 switch (tip->type) {
396 case T_ORDREL_IND:
397 case T_DISCON_IND:
398 /* Make into M_HANGUP and putnext */
399 mp->b_datap->db_type = M_HANGUP;
400 mp->b_wptr = mp->b_rptr;
401 if (mp->b_cont) {
402 freemsg(mp->b_cont);
403 mp->b_cont = NULL;
406 * If we haven't already, send T_UNBIND_REQ to prevent
407 * TCP from going into "BOUND" state and locking up the
408 * port.
410 if (tip->type == T_DISCON_IND && rmip->unbind_mp !=
411 NULL) {
412 putnext(q, mp);
413 qreply(q, rmip->unbind_mp);
414 rmip->unbind_mp = NULL;
415 } else {
416 putnext(q, mp);
418 break;
421 * We only get T_OK_ACK when we issue the unbind, and it can
422 * be ignored safely.
424 case T_OK_ACK:
425 ASSERT(rmip->unbind_mp == NULL);
426 freemsg(mp);
427 break;
429 default:
430 cmn_err(CE_NOTE,
431 "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
432 tip->type);
433 freemsg(mp);
435 break;
437 case M_DATA:
438 if (canputnext(q) && q->q_first == NULL) {
439 (void) rlmodrmsg(q, mp);
440 } else {
441 (void) putq(q, mp);
443 break;
445 case M_FLUSH:
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)
453 flushq(q, FLUSHALL);
455 putnext(q, mp);
456 break;
458 case M_PCSIG:
459 case M_ERROR:
460 case M_IOCACK:
461 case M_IOCNAK:
462 case M_SETOPTS:
463 if (mp->b_datap->db_type <= QPCTL && !canputnext(q))
464 (void) putq(q, mp);
465 else
466 putnext(q, mp);
467 break;
469 default:
470 #ifdef DEBUG
471 cmn_err(CE_NOTE, "rlmodrput: unexpected msg type 0x%x",
472 mp->b_datap->db_type);
473 #endif
474 freemsg(mp);
476 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT, "rlmodrput end: q %p, "
477 "mp %p, %s", q, mp, "done");
478 return (0);
482 * rlmodrsrv - module read service procedure
484 static int
485 rlmodrsrv(queue_t *q)
487 mblk_t *mp;
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: "
492 "q %p", q);
493 while ((mp = getq(q)) != NULL) {
495 switch (mp->b_datap->db_type) {
496 case M_DATA:
497 if (rmip->flags & RL_DISABLED) {
498 (void) putbq(q, mp);
499 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
500 "rlmodrsrv end: q %p, mp %p, %s", q, mp,
501 "disabled");
502 return (0);
504 if (!canputnext(q)) {
505 (void) putbq(q, mp);
506 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
507 "rlmodrsrv end: q %p, mp %p, %s",
508 q, mp, "!canputnext");
509 return (0);
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");
515 return (0);
517 break;
519 case M_PROTO:
520 tip = (union T_primitives *)mp->b_rptr;
521 switch (tip->type) {
523 case T_ORDREL_IND:
524 case T_DISCON_IND:
525 /* Make into M_HANGUP and putnext */
526 mp->b_datap->db_type = M_HANGUP;
527 mp->b_wptr = mp->b_rptr;
528 if (mp->b_cont) {
529 freemsg(mp->b_cont);
530 mp->b_cont = NULL;
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) {
539 putnext(q, mp);
540 qreply(q, rmip->unbind_mp);
541 rmip->unbind_mp = NULL;
542 } else {
543 putnext(q, mp);
545 break;
548 * We only get T_OK_ACK when we issue the unbind, and
549 * it can be ignored safely.
551 case T_OK_ACK:
552 ASSERT(rmip->unbind_mp == NULL);
553 freemsg(mp);
554 break;
556 default:
557 cmn_err(CE_NOTE,
558 "rlmodrsrv: got 0x%x type PROTO msg",
559 tip->type);
560 freemsg(mp);
562 break;
564 case M_SETOPTS:
565 if (!canputnext(q)) {
566 (void) putbq(q, mp);
567 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
568 "rlmodrsrv end: q %p, mp %p, %s",
569 q, mp, "!canputnext M_SETOPTS");
570 return (0);
572 putnext(q, mp);
573 break;
575 default:
576 #ifdef DEBUG
577 cmn_err(CE_NOTE,
578 "rlmodrsrv: unexpected msg type 0x%x",
579 mp->b_datap->db_type);
580 #endif
581 freemsg(mp);
585 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT, "rlmodrsrv end: q %p, "
586 "mp %p, %s", q, mp, "empty");
588 return (0);
592 * rlmodwput - Module write queue put procedure.
593 * All non-zero messages are send downstream unchanged
595 static int
596 rlmodwput(queue_t *q, mblk_t *mp)
598 char cntl;
599 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
600 mblk_t *tmpmp;
601 int rw;
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
609 * message block.
611 cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
613 if (!canputnext(q)) {
614 (void) putq(q, mp);
615 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
616 "rlmodwput end: q %p, mp %p, %s",
617 q, mp, "expdata && !canputnext");
618 return (0);
620 if ((tmpmp = make_expmblk(cntl))) {
621 putnext(q, tmpmp);
622 rmip->rl_expdat = 0;
623 } else {
624 recover1(q, sizeof (mblk_t)); /* XXX.sparker */
628 if ((q->q_first || rmip->rl_expdat) && mp->b_datap->db_type < QPCTL) {
629 (void) putq(q, mp);
630 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
631 "q %p, mp %p, %s", q, mp, "queued data");
632 return (0);
634 switch (mp->b_datap->db_type) {
636 case M_DATA:
637 if (!canputnext(q))
638 (void) putq(q, mp);
639 else
640 putnext(q, mp);
641 break;
643 case M_FLUSH:
645 * We must take care to create and forward out-of-band data
646 * indicating the flush to the far side.
648 rw = *mp->b_rptr;
649 *mp->b_rptr &= ~FLUSHW;
650 qreply(q, mp);
651 if (rw & 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
667 * hold.
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");
678 return (0);
680 if ((mp = make_expmblk(cntl)) == NULL) {
681 rmip->rl_expdat = 1;
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");
686 return (0);
688 putnext(q, mp);
690 break;
692 case M_IOCTL:
693 if (!rlmodwioctl(q, mp))
694 (void) putq(q, mp);
695 break;
697 case M_PROTO:
698 switch (((union T_primitives *)mp->b_rptr)->type) {
699 case T_EXDATA_REQ:
700 case T_ORDREL_REQ:
701 case T_DISCON_REQ:
702 putnext(q, mp);
703 break;
705 default:
706 #ifdef DEBUG
707 cmn_err(CE_NOTE,
708 "rlmodwput: unexpected TPI primitive 0x%x",
709 ((union T_primitives *)mp->b_rptr)->type);
710 #endif
711 freemsg(mp);
713 break;
715 case M_PCPROTO:
716 if (((struct T_exdata_req *)mp->b_rptr)->PRIM_type ==
717 T_DISCON_REQ) {
718 putnext(q, mp);
719 } else {
720 /* XXX.sparker Log unexpected message */
721 freemsg(mp);
723 break;
725 default:
726 #ifdef DEBUG
727 cmn_err(CE_NOTE,
728 "rlmodwput: unexpected msg type 0x%x",
729 mp->b_datap->db_type);
730 #endif
731 freemsg(mp);
732 break;
734 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
735 "q %p, mp %p, %s", q, mp, "done");
736 return (0);
740 * rlmodwsrv - module write service procedure
742 static int
743 rlmodwsrv(queue_t *q)
745 mblk_t *mp, *tmpmp;
746 char cntl;
747 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
749 TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_IN, "rlmodwsrv "
750 "start: q %p", q);
751 if (rmip->rl_expdat) {
753 * call make_expmblk to create an expedited
754 * message block.
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");
761 return (0);
763 if ((tmpmp = make_expmblk(cntl))) {
764 putnext(q, tmpmp);
765 rmip->rl_expdat = 0;
766 } else {
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");
771 return (0);
774 while ((mp = getq(q)) != NULL) {
776 if (!canputnext(q) || rmip->rl_expdat) {
777 (void) putbq(q, mp);
778 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
779 "rlmodwsrv end: q %p, mp %p, %s",
780 q, mp, "!canputnext || expdat");
781 return (0);
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");
788 (void) putbq(q, mp);
789 return (0);
791 continue;
793 putnext(q, mp);
795 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT, "rlmodwsrv end: q %p, "
796 "mp %p, %s", q, mp, "done");
797 return (0);
801 * This routine returns a message block with an expedited
802 * data request
804 static mblk_t *
805 make_expmblk(char cntl)
807 mblk_t *mp;
808 mblk_t *bp;
809 struct T_exdata_req *data_req;
811 bp = allocb(sizeof (struct T_exdata_req), BPRI_MED);
812 if (bp == NULL)
813 return (NULL);
814 if ((mp = allocb(sizeof (char), BPRI_MED)) == NULL) {
815 freeb(bp);
816 return (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
826 * control character.
828 mp->b_datap->db_type = M_DATA;
829 mp->b_wptr = mp->b_rptr + 1;
830 (*(char *)(mp->b_rptr)) = cntl;
831 bp->b_cont = mp;
832 return (bp);
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.
840 static int
841 rlmodrmsg(queue_t *q, mblk_t *mp)
843 unsigned char *tmp, *tmp1;
844 mblk_t *newmp;
845 size_t sz;
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
851 * accidentally.
853 if (msgdsize(mp) == 0) {
854 ASSERT(rmip->wndw_sz_hd_mp == NULL);
855 goto out;
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;
867 newmp = mp;
869 while (mp) {
870 tmp = mp->b_rptr;
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);
890 return (NULL);
893 * pullupmsg results in newmp consuming
894 * all message blocks in this chain, and
895 * therefor mp wants updating.
897 mp = newmp;
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;
906 newcount = 0;
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;
925 return (TRUE);
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) {
944 sz = msgdsize(mp);
945 recover(q, mp, sz);
946 return (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
955 * to rescan it.
957 continue;
960 tmp++;
963 * bump newcount to include size of this particular block.
965 newcount += (mp->b_wptr - mp->b_rptr);
966 mp = mp->b_cont;
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) {
973 freemsg(newmp);
974 newmp = NULL;
976 out:
977 if (newmp) {
978 if (!canputnext(q)) {
979 (void) putbq(q, newmp);
980 return (NULL);
981 } else {
982 putnext(q, newmp);
985 return (TRUE);
990 * This routine is called to handle window size changes.
991 * The routine returns 1 on success and 0 on error (allocb failure).
993 static int
994 rlwinctl(queue_t *q, mblk_t *mp)
996 mblk_t *rl_msgp;
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, "
1001 "mp %p", q, mp);
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);
1008 return (0);
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);
1021 return (1);
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.
1030 static mblk_t *
1031 rlwinsetup(queue_t *q, mblk_t *mp, unsigned char *blk)
1033 mblk_t *mp1;
1034 unsigned char *jmpmp;
1035 ssize_t left = 0;
1036 struct winsize win;
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)
1046 return (0);
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) {
1057 freeb(mp1);
1058 return (0);
1060 if (left > 0) {
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;
1068 } else
1069 mp->b_wptr = blk;
1070 return (mp);
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.
1083 static boolean_t
1084 tty_flow(queue_t *q, struct rlmod_info *rmip, mblk_t *mp)
1086 struct iocblk *ioc;
1087 struct termios *tp;
1088 struct termio *ti;
1089 int stop, ixon;
1090 mblk_t *tmpmp;
1091 char cntl;
1092 int error;
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.
1102 case TCSETS:
1103 case TCSETSW:
1104 case TCSETSF:
1105 error = miocpullup(mp, sizeof (struct termios));
1106 if (error != 0) {
1107 miocnak(q, mp, 0, error);
1108 return (B_TRUE);
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;
1114 break;
1116 case TCSETA:
1117 case TCSETAW:
1118 case TCSETAF:
1119 error = miocpullup(mp, sizeof (struct termio));
1120 if (error != 0) {
1121 miocnak(q, mp, 0, error);
1122 return (B_TRUE);
1124 ti = (struct termio *)(mp->b_cont->b_rptr);
1125 ixon = ti->c_iflag & IXON;
1126 break;
1128 default:
1130 * This function must never be called for an M_IOCTL
1131 * except the listed ones.
1133 #ifdef DEBUG
1134 cmn_err(CE_PANIC,
1135 "rloginmod: tty_flow: bad ioctl 0x%x", ioc->ioc_cmd);
1136 #else
1137 miocnak(q, mp, 0, EINVAL);
1138 return (B_TRUE);
1139 #endif
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) {
1147 if (stop) {
1148 cntl = rmip->oobdata[0] | TIOCPKT_DOSTOP;
1149 if ((tmpmp = make_expmblk(cntl)) == NULL) {
1150 recover(q, mp, sizeof (mblk_t));
1151 return (B_FALSE);
1153 if (!canputnext(q)) {
1154 freemsg(tmpmp);
1155 return (B_FALSE);
1157 putnext(q, tmpmp);
1158 rmip->stopmode = TIOCPKT_DOSTOP;
1160 } else {
1161 if (!stop) {
1162 cntl = rmip->oobdata[0] | TIOCPKT_NOSTOP;
1163 if ((tmpmp = make_expmblk(cntl)) == NULL) {
1164 recover(q, mp, sizeof (mblk_t));
1165 return (B_FALSE);
1167 if (!canputnext(q)) {
1168 freemsg(tmpmp);
1169 return (B_FALSE);
1171 putnext(q, tmpmp);
1172 rmip->stopmode = TIOCPKT_NOSTOP;
1176 miocack(q, mp, 0, 0);
1177 return (B_TRUE);
1180 /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
1182 static boolean_t
1183 rlmodwioctl(queue_t *q, mblk_t *mp)
1185 struct iocblk *ioc;
1186 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1187 int error;
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.
1197 case RL_IOC_ENABLE:
1199 * Send negative ack if RL_DISABLED flag is not set
1202 if (!(rmip->flags & RL_DISABLED)) {
1203 miocnak(q, mp, 0, EINVAL);
1204 break;
1206 if (mp->b_cont) {
1207 (void) putbq(RD(q), mp->b_cont);
1208 mp->b_cont = NULL;
1211 if (rmip->flags & RL_DISABLED)
1212 rmip->flags &= ~RL_DISABLED;
1213 qenable(RD(q));
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");
1218 return (B_TRUE);
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.
1225 case TCSETS:
1226 case TCSETSW:
1227 case TCSETSF:
1228 case TCSETA:
1229 case TCSETAW:
1230 case TCSETAF:
1231 return (tty_flow(q, rmip, mp));
1233 #ifdef DEBUG
1234 case TIOCSWINSZ:
1235 case TIOCSTI:
1236 case TCSBRK:
1237 miocnak(q, mp, 0, EINVAL);
1238 break;
1239 #endif
1240 case CRYPTPASSTHRU:
1241 error = miocpullup(mp, sizeof (uchar_t));
1242 if (error != 0) {
1243 miocnak(q, mp, 0, error);
1244 break;
1246 if (*(mp->b_cont->b_rptr) == 0x01)
1247 rmip->flags |= RL_IOCPASSTHRU;
1248 else
1249 rmip->flags &= ~RL_IOCPASSTHRU;
1251 miocack(q, mp, NULL, 0);
1252 break;
1254 default:
1255 if (rmip->flags & RL_IOCPASSTHRU) {
1256 putnext(q, mp);
1257 } else {
1258 #ifdef DEBUG
1259 cmn_err(CE_NOTE,
1260 "rlmodwioctl: unexpected ioctl type 0x%x",
1261 ioc->ioc_cmd);
1262 #endif
1263 miocnak(q, mp, 0, EINVAL);
1266 return (B_TRUE);
1269 static void
1270 rlmod_timer(void *arg)
1272 queue_t *q = arg;
1273 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1275 ASSERT(rmip);
1276 if (q->q_flag & QREADR) {
1277 ASSERT(rmip->rtimoutid);
1278 rmip->rtimoutid = 0;
1279 } else {
1280 ASSERT(rmip->wtimoutid);
1281 rmip->wtimoutid = 0;
1283 enableok(q);
1284 qenable(q);
1287 static void
1288 rlmod_buffer(void *arg)
1290 queue_t *q = arg;
1291 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1293 ASSERT(rmip);
1294 if (q->q_flag & QREADR) {
1295 ASSERT(rmip->rbufcid);
1296 rmip->rbufcid = 0;
1297 } else {
1298 ASSERT(rmip->wbufcid);
1299 rmip->wbufcid = 0;
1301 enableok(q);
1302 qenable(q);
1305 static void
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);
1313 noenable(q);
1314 (void) putbq(q, mp);
1315 recover1(q, size);
1318 static void
1319 recover1(queue_t *q, size_t size)
1321 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1322 timeout_id_t tid;
1323 bufcall_id_t bid;
1326 * Make sure there is at most one outstanding request per queue.
1328 if (q->q_flag & QREADR) {
1329 if (rmip->rtimoutid || rmip->rbufcid)
1330 return;
1331 } else {
1332 if (rmip->wtimoutid || rmip->wbufcid)
1333 return;
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;
1339 else
1340 rmip->wtimoutid = tid;
1341 } else {
1342 if (q->q_flag & QREADR)
1343 rmip->rbufcid = bid;
1344 else
1345 rmip->wbufcid = bid;