1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This module implements the services provided by the rlogin daemon
29 * after the connection is set up. Mainly this means responding to
30 * interrupts and window size changes. It begins operation in "disabled"
31 * state, and sends a T_DATA_REQ to the daemon to indicate that it is
32 * in place and ready to be enabled. The daemon can then know when all
33 * data which sneaked passed rlmod (before it was pushed) has been received.
34 * The daemon may process this data, or send data back to be inserted in
35 * the read queue at the head with the RL_IOC_ENABLE ioctl.
36 */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/stream.h>
41 #include <sys/stropts.h>
42 #include <sys/strsun.h>
43 #include <sys/kmem.h>
44 #include <sys/errno.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/tihdr.h>
48 #include <sys/ptem.h>
49 #include <sys/conf.h>
50 #include <sys/debug.h>
51 #include <sys/modctl.h>
52 #include <sys/vtrace.h>
53 #include <sys/rlioctl.h>
54 #include <sys/termios.h>
55 #include <sys/termio.h>
56 #include <sys/byteorder.h>
57 #include <sys/cmn_err.h>
58 #include <sys/cryptmod.h>
59
60 extern struct streamtab rloginmodinfo;
61
62 static struct fmodsw fsw = {
63 "rlmod",
64 &rloginmodinfo,
65 D_MTQPAIR | D_MP
66 };
67
68 /*
69 * Module linkage information for the kernel.
70 */
71
72 static struct modlstrmod modlstrmod = {
73 &mod_strmodops,
74 "rloginmod module",
75 &fsw
76 };
77
78 static struct modlinkage modlinkage = {
79 MODREV_1, { &modlstrmod, NULL }
80 };
81
82
83 int
84 _init(void)
85 {
86 return (mod_install(&modlinkage));
87 }
88
89 int
90 _fini(void)
91 {
92 return (mod_remove(&modlinkage));
93 }
94
95 int
96 _info(struct modinfo *modinfop)
97 {
98 return (mod_info(&modlinkage, modinfop));
99 }
100
101 struct rlmod_info; /* forward reference for function prototype */
102
103 static int rlmodopen(queue_t *, dev_t *, int, int, cred_t *);
104 static int rlmodclose(queue_t *, int, cred_t *);
105 static int rlmodrput(queue_t *, mblk_t *);
106 static int rlmodrsrv(queue_t *);
107 static int rlmodwput(queue_t *, mblk_t *);
108 static int rlmodwsrv(queue_t *);
109 static int rlmodrmsg(queue_t *, mblk_t *);
110 static mblk_t *make_expmblk(char);
111 static int rlwinctl(queue_t *, mblk_t *);
112 static mblk_t *rlwinsetup(queue_t *, mblk_t *, unsigned char *);
113
114 static void rlmod_timer(void *);
115 static void rlmod_buffer(void *);
116 static boolean_t tty_flow(queue_t *, struct rlmod_info *, mblk_t *);
117 static boolean_t rlmodwioctl(queue_t *, mblk_t *);
118 static void recover(queue_t *, mblk_t *, size_t);
119 static void recover1(queue_t *, size_t);
120
121 #define RLMOD_ID 106
122 #define SIMWAIT (1*hz)
123
124 /*
125 * Stream module data structure definitions.
126 * generally pushed onto tcp by rlogin daemon
127 *
128 */
129 static struct module_info rloginmodiinfo = {
130 RLMOD_ID, /* module id number */
131 "rlmod", /* module name */
132 0, /* minimum packet size */
133 INFPSZ, /* maximum packet size */
134 512, /* hi-water mark */
135 256 /* lo-water mark */
136 };
137
138 static struct qinit rloginmodrinit = {
139 rlmodrput,
140 rlmodrsrv,
141 rlmodopen,
142 rlmodclose,
143 nulldev,
144 &rloginmodiinfo,
145 NULL
146 };
147
148 static struct qinit rloginmodwinit = {
149 rlmodwput,
150 rlmodwsrv,
151 NULL,
152 NULL,
153 nulldev,
154 &rloginmodiinfo,
155 NULL
156 };
157
158 struct streamtab rloginmodinfo = {
159 &rloginmodrinit,
160 &rloginmodwinit,
161 NULL,
162 NULL
163 };
164
165 /*
166 * Per-instance state struct for the rloginmod module.
167 */
168 struct rlmod_info
169 {
170 int flags;
171 bufcall_id_t wbufcid;
172 bufcall_id_t rbufcid;
173 timeout_id_t wtimoutid;
174 timeout_id_t rtimoutid;
175 int rl_expdat;
176 int stopmode;
177 mblk_t *unbind_mp;
178 char startc;
179 char stopc;
180 char oobdata[1];
181 mblk_t *wndw_sz_hd_mp;
182 };
183
184 /*
185 * Flag used in flags
186 */
187 #define RL_DISABLED 0x1
188 #define RL_IOCPASSTHRU 0x2
189
190 /*ARGSUSED*/
191 static void
192 dummy_callback(void *arg)
193 {}
194
195 /*
196 * rlmodopen - open routine gets called when the
197 * module gets pushed onto the stream.
198 */
199 /*ARGSUSED*/
200 static int
201 rlmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *cred)
202 {
203 struct rlmod_info *rmip;
204 union T_primitives *tp;
205 mblk_t *bp;
206 int error;
207
208 if (sflag != MODOPEN)
209 return (EINVAL);
210
211 if (q->q_ptr != NULL) {
212 /* It's already attached. */
213 return (0);
214 }
215
216 /*
217 * Allocate state structure.
218 */
219 rmip = kmem_zalloc(sizeof (*rmip), KM_SLEEP);
220
221 /*
222 * Cross-link.
223 */
224 q->q_ptr = rmip;
225 WR(q)->q_ptr = rmip;
226 rmip->rl_expdat = 0;
227 rmip->stopmode = TIOCPKT_DOSTOP;
228 rmip->startc = CTRL('q');
229 rmip->stopc = CTRL('s');
230 rmip->oobdata[0] = (char)TIOCPKT_WINDOW;
231 rmip->wndw_sz_hd_mp = NULL;
232 /*
233 * Allow only non-M_DATA blocks to pass up to in.rlogind until
234 * it is ready for M_DATA (indicated by RL_IOC_ENABLE).
235 */
236 rmip->flags |= RL_DISABLED;
237
238 qprocson(q);
239
240 /*
241 * Since TCP operates in the TLI-inspired brain-dead fashion,
242 * the connection will revert to bound state if the connection
243 * is reset by the client. We must send a T_UNBIND_REQ in
244 * that case so the port doesn't get "wedged" (preventing
245 * inetd from being able to restart the listener). Allocate
246 * it here, so that we don't need to worry about allocb()
247 * failures later.
248 */
249 while ((rmip->unbind_mp = allocb(sizeof (union T_primitives),
250 BPRI_HI)) == NULL) {
251 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
252 BPRI_HI, dummy_callback, NULL);
253 if (!qwait_sig(q)) {
254 qunbufcall(q, id);
255 error = EINTR;
256 goto fail;
257 }
258 qunbufcall(q, id);
259 }
260 rmip->unbind_mp->b_wptr = rmip->unbind_mp->b_rptr +
261 sizeof (struct T_unbind_req);
262 rmip->unbind_mp->b_datap->db_type = M_PROTO;
263 tp = (union T_primitives *)rmip->unbind_mp->b_rptr;
264 tp->type = T_UNBIND_REQ;
265
266 /*
267 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
268 * read queue since only write queue can get T_DATA_REQ).
269 * Readstream routine in the daemon will do a getmsg() till
270 * it receives this proto message.
271 */
272 while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) {
273 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
274 BPRI_HI, dummy_callback, NULL);
275 if (!qwait_sig(q)) {
276 qunbufcall(q, id);
277 error = EINTR;
278 goto fail;
279 }
280 qunbufcall(q, id);
281 }
282 bp->b_datap->db_type = M_PROTO;
283 bp->b_wptr = bp->b_rptr + sizeof (union T_primitives);
284 tp = (union T_primitives *)bp->b_rptr;
285 tp->type = T_DATA_REQ;
286 tp->data_req.MORE_flag = 0;
287
288 putnext(q, bp);
289 return (0);
290 fail:
291 qprocsoff(q);
292 if (rmip->unbind_mp != NULL) {
293 freemsg(rmip->unbind_mp);
294 }
295 kmem_free(rmip, sizeof (struct rlmod_info));
296 q->q_ptr = NULL;
297 WR(q)->q_ptr = NULL;
298 return (error);
299 }
300
301
302 /*
303 * rlmodclose - This routine gets called when the module
304 * gets popped off of the stream.
305 */
306
307 /*ARGSUSED*/
308 static int
309 rlmodclose(queue_t *q, int flag, cred_t *credp)
310 {
311 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
312 mblk_t *mp;
313
314 /*
315 * Flush any write-side data downstream. Ignoring flow
316 * control at this point is known to be safe because the
317 * M_HANGUP below poisons the stream such that no modules can
318 * be pushed again.
319 */
320 while (mp = getq(WR(q)))
321 putnext(WR(q), mp);
322
323 /* Poison the stream head so that we can't be pushed again. */
324 (void) putnextctl(q, M_HANGUP);
325
326 qprocsoff(q);
327 if (rmip->wbufcid) {
328 qunbufcall(q, rmip->wbufcid);
329 rmip->wbufcid = 0;
330 }
331 if (rmip->rbufcid) {
332 qunbufcall(q, rmip->rbufcid);
333 rmip->rbufcid = 0;
334 }
335 if (rmip->wtimoutid) {
336 (void) quntimeout(q, rmip->wtimoutid);
337 rmip->wtimoutid = 0;
338 }
339 if (rmip->rtimoutid) {
340 (void) quntimeout(q, rmip->rtimoutid);
341 rmip->rtimoutid = 0;
342 }
343
344 if (rmip->unbind_mp != NULL) {
345 freemsg(rmip->unbind_mp);
346 }
347
348 if (rmip->wndw_sz_hd_mp != NULL) {
349 freemsg(rmip->wndw_sz_hd_mp);
350 }
351
352 kmem_free(q->q_ptr, sizeof (struct rlmod_info));
353 q->q_ptr = WR(q)->q_ptr = NULL;
354 return (0);
355 }
356
357 /*
358 * rlmodrput - Module read queue put procedure.
359 * This is called from the module or
360 * driver downstream.
361 */
362
363 static int
364 rlmodrput(queue_t *q, mblk_t *mp)
365 {
366 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
367 union T_primitives *tip;
368
369 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_IN, "rlmodrput start: "
370 "q %p, mp %p", q, mp);
371
372
373 /* if low (normal) priority... */
374 if ((mp->b_datap->db_type < QPCTL) &&
375 /* ...and data is already queued... */
376 ((q->q_first) ||
377 /* ...or currently disabled and this is M_DATA... */
378 ((rmip->flags & RL_DISABLED) &&
379 (mp->b_datap->db_type == M_DATA)))) {
380 /* ...delay delivery of the message */
381 (void) putq(q, mp);
382 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT,
383 "rlmodrput end: q %p, mp %p, %s", q, mp, "flow");
384 return (0);
385 }
386
387 switch (mp->b_datap->db_type) {
388
389 case M_PROTO:
390 case M_PCPROTO:
391 tip = (union T_primitives *)mp->b_rptr;
392 switch (tip->type) {
393
394 case T_ORDREL_IND:
395 case T_DISCON_IND:
396 /* Make into M_HANGUP and putnext */
397 mp->b_datap->db_type = M_HANGUP;
398 mp->b_wptr = mp->b_rptr;
399 if (mp->b_cont) {
400 freemsg(mp->b_cont);
401 mp->b_cont = NULL;
402 }
403 /*
404 * If we haven't already, send T_UNBIND_REQ to prevent
405 * TCP from going into "BOUND" state and locking up the
406 * port.
407 */
408 if (tip->type == T_DISCON_IND && rmip->unbind_mp !=
409 NULL) {
410 putnext(q, mp);
411 qreply(q, rmip->unbind_mp);
412 rmip->unbind_mp = NULL;
413 } else {
414 putnext(q, mp);
415 }
416 break;
417
418 /*
419 * We only get T_OK_ACK when we issue the unbind, and it can
420 * be ignored safely.
421 */
422 case T_OK_ACK:
423 ASSERT(rmip->unbind_mp == NULL);
424 freemsg(mp);
425 break;
426
427 default:
428 cmn_err(CE_NOTE,
429 "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
430 tip->type);
431 freemsg(mp);
432 }
433 break;
434
435 case M_DATA:
436 if (canputnext(q) && q->q_first == NULL) {
437 (void) rlmodrmsg(q, mp);
438 } else {
439 (void) putq(q, mp);
440 }
441 break;
442
443 case M_FLUSH:
444 /*
445 * Since M_FLUSH came from TCP, we mark it bound for
446 * daemon, not tty. This only happens when TCP expects
447 * to do a connection reset.
448 */
449 mp->b_flag |= MSGMARK;
450 if (*mp->b_rptr & FLUSHR)
451 flushq(q, FLUSHALL);
452
453 putnext(q, mp);
454 break;
455
456 case M_PCSIG:
457 case M_ERROR:
458 case M_IOCACK:
459 case M_IOCNAK:
460 case M_SETOPTS:
461 if (mp->b_datap->db_type <= QPCTL && !canputnext(q))
462 (void) putq(q, mp);
463 else
464 putnext(q, mp);
465 break;
466
467 default:
468 #ifdef DEBUG
469 cmn_err(CE_NOTE, "rlmodrput: unexpected msg type 0x%x",
470 mp->b_datap->db_type);
471 #endif
472 freemsg(mp);
473 }
474 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT, "rlmodrput end: q %p, "
475 "mp %p, %s", q, mp, "done");
476 return (0);
477 }
478
479 /*
480 * rlmodrsrv - module read service procedure
481 */
482 static int
483 rlmodrsrv(queue_t *q)
484 {
485 mblk_t *mp;
486 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
487 union T_primitives *tip;
488
489 TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_IN, "rlmodrsrv start: "
490 "q %p", q);
491 while ((mp = getq(q)) != NULL) {
492
493 switch (mp->b_datap->db_type) {
494 case M_DATA:
495 if (rmip->flags & RL_DISABLED) {
496 (void) putbq(q, mp);
497 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
498 "rlmodrsrv end: q %p, mp %p, %s", q, mp,
499 "disabled");
500 return (0);
501 }
502 if (!canputnext(q)) {
503 (void) putbq(q, mp);
504 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
505 "rlmodrsrv end: q %p, mp %p, %s",
506 q, mp, "!canputnext");
507 return (0);
508 }
509 if (!rlmodrmsg(q, mp)) {
510 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
511 "rlmodrsrv end: q %p, mp %p, %s",
512 q, mp, "!rlmodrmsg");
513 return (0);
514 }
515 break;
516
517 case M_PROTO:
518 tip = (union T_primitives *)mp->b_rptr;
519 switch (tip->type) {
520
521 case T_ORDREL_IND:
522 case T_DISCON_IND:
523 /* Make into M_HANGUP and putnext */
524 mp->b_datap->db_type = M_HANGUP;
525 mp->b_wptr = mp->b_rptr;
526 if (mp->b_cont) {
527 freemsg(mp->b_cont);
528 mp->b_cont = NULL;
529 }
530 /*
531 * If we haven't already, send T_UNBIND_REQ
532 * to prevent TCP from going into "BOUND"
533 * state and locking up the port.
534 */
535 if (tip->type == T_DISCON_IND &&
536 rmip->unbind_mp != NULL) {
537 putnext(q, mp);
538 qreply(q, rmip->unbind_mp);
539 rmip->unbind_mp = NULL;
540 } else {
541 putnext(q, mp);
542 }
543 break;
544
545 /*
546 * We only get T_OK_ACK when we issue the unbind, and
547 * it can be ignored safely.
548 */
549 case T_OK_ACK:
550 ASSERT(rmip->unbind_mp == NULL);
551 freemsg(mp);
552 break;
553
554 default:
555 cmn_err(CE_NOTE,
556 "rlmodrsrv: got 0x%x type PROTO msg",
557 tip->type);
558 freemsg(mp);
559 }
560 break;
561
562 case M_SETOPTS:
563 if (!canputnext(q)) {
564 (void) putbq(q, mp);
565 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT,
566 "rlmodrsrv end: q %p, mp %p, %s",
567 q, mp, "!canputnext M_SETOPTS");
568 return (0);
569 }
570 putnext(q, mp);
571 break;
572
573 default:
574 #ifdef DEBUG
575 cmn_err(CE_NOTE,
576 "rlmodrsrv: unexpected msg type 0x%x",
577 mp->b_datap->db_type);
578 #endif
579 freemsg(mp);
580 }
581 }
582
583 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT, "rlmodrsrv end: q %p, "
584 "mp %p, %s", q, mp, "empty");
585
586 return (0);
587 }
588
589 /*
590 * rlmodwput - Module write queue put procedure.
591 * All non-zero messages are send downstream unchanged
592 */
593 static int
594 rlmodwput(queue_t *q, mblk_t *mp)
595 {
596 char cntl;
597 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
598 mblk_t *tmpmp;
599 int rw;
600
601 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_IN, "rlmodwput start: "
602 "q %p, mp %p", q, mp);
603
604 if (rmip->rl_expdat) {
605 /*
606 * call make_expmblk to create an expedited
607 * message block.
608 */
609 cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
610
611 if (!canputnext(q)) {
612 (void) putq(q, mp);
613 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
614 "rlmodwput end: q %p, mp %p, %s",
615 q, mp, "expdata && !canputnext");
616 return (0);
617 }
618 if ((tmpmp = make_expmblk(cntl))) {
619 putnext(q, tmpmp);
620 rmip->rl_expdat = 0;
621 } else {
622 recover1(q, sizeof (mblk_t)); /* XXX.sparker */
623 }
624 }
625
626 if ((q->q_first || rmip->rl_expdat) && mp->b_datap->db_type < QPCTL) {
627 (void) putq(q, mp);
628 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
629 "q %p, mp %p, %s", q, mp, "queued data");
630 return (0);
631 }
632 switch (mp->b_datap->db_type) {
633
634 case M_DATA:
635 if (!canputnext(q))
636 (void) putq(q, mp);
637 else
638 putnext(q, mp);
639 break;
640
641 case M_FLUSH:
642 /*
643 * We must take care to create and forward out-of-band data
644 * indicating the flush to the far side.
645 */
646 rw = *mp->b_rptr;
647 *mp->b_rptr &= ~FLUSHW;
648 qreply(q, mp);
649 if (rw & FLUSHW) {
650 /*
651 * Since all rlogin protocol data is sent in this
652 * direction as urgent data, and TCP does not flush
653 * urgent data, it is okay to actually forward this
654 * flush. (telmod cannot.)
655 */
656 flushq(q, FLUSHDATA);
657 /*
658 * The putnextctl1() call can only fail if we're
659 * out of memory. Ideally, we might set a state
660 * bit and reschedule ourselves when memory
661 * becomes available, so we make sure not to miss
662 * sending the FLUSHW to TCP before the urgent
663 * byte. Not doing this just means in some cases
664 * a bit more trash passes before the flush takes
665 * hold.
666 */
667 (void) putnextctl1(q, M_FLUSH, FLUSHW);
668 /*
669 * Notify peer of the write flush request.
670 */
671 cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
672 if (!canputnext(q)) {
673 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
674 "rlmodwput end: q %p, mp %p, %s",
675 q, mp, "flushw && !canputnext");
676 return (0);
677 }
678 if ((mp = make_expmblk(cntl)) == NULL) {
679 rmip->rl_expdat = 1;
680 recover1(q, sizeof (mblk_t));
681 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
682 "rlmodwput end: q %p, mp %p, %s",
683 q, mp, "!make_expmblk");
684 return (0);
685 }
686 putnext(q, mp);
687 }
688 break;
689
690 case M_IOCTL:
691 if (!rlmodwioctl(q, mp))
692 (void) putq(q, mp);
693 break;
694
695 case M_PROTO:
696 switch (((union T_primitives *)mp->b_rptr)->type) {
697 case T_EXDATA_REQ:
698 case T_ORDREL_REQ:
699 case T_DISCON_REQ:
700 putnext(q, mp);
701 break;
702
703 default:
704 #ifdef DEBUG
705 cmn_err(CE_NOTE,
706 "rlmodwput: unexpected TPI primitive 0x%x",
707 ((union T_primitives *)mp->b_rptr)->type);
708 #endif
709 freemsg(mp);
710 }
711 break;
712
713 case M_PCPROTO:
714 if (((struct T_exdata_req *)mp->b_rptr)->PRIM_type ==
715 T_DISCON_REQ) {
716 putnext(q, mp);
717 } else {
718 /* XXX.sparker Log unexpected message */
719 freemsg(mp);
720 }
721 break;
722
723 default:
724 #ifdef DEBUG
725 cmn_err(CE_NOTE,
726 "rlmodwput: unexpected msg type 0x%x",
727 mp->b_datap->db_type);
728 #endif
729 freemsg(mp);
730 break;
731 }
732 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
733 "q %p, mp %p, %s", q, mp, "done");
734 return (0);
735 }
736
737 /*
738 * rlmodwsrv - module write service procedure
739 */
740 static int
741 rlmodwsrv(queue_t *q)
742 {
743 mblk_t *mp, *tmpmp;
744 char cntl;
745 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
746
747 TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_IN, "rlmodwsrv "
748 "start: q %p", q);
749 if (rmip->rl_expdat) {
750 /*
751 * call make_expmblk to create an expedited
752 * message block.
753 */
754 cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
755 if (!canputnext(q)) {
756 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
757 "rlmodwsrv end: q %p, mp %p, %s",
758 q, NULL, "!canputnext && expdat");
759 return (0);
760 }
761 if ((tmpmp = make_expmblk(cntl))) {
762 putnext(q, tmpmp);
763 rmip->rl_expdat = 0;
764 } else {
765 recover1(q, sizeof (mblk_t));
766 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
767 "rlmodwsrv end: q %p, mp %p, %s",
768 q, NULL, "!make_expmblk");
769 return (0);
770 }
771 }
772 while ((mp = getq(q)) != NULL) {
773
774 if (!canputnext(q) || rmip->rl_expdat) {
775 (void) putbq(q, mp);
776 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
777 "rlmodwsrv end: q %p, mp %p, %s",
778 q, mp, "!canputnext || expdat");
779 return (0);
780 }
781 if (mp->b_datap->db_type == M_IOCTL) {
782 if (!rlmodwioctl(q, mp)) {
783 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT,
784 "rlmodwsrv end: q %p, mp %p, %s",
785 q, mp, "!rlmodwioctl");
786 (void) putbq(q, mp);
787 return (0);
788 }
789 continue;
790 }
791 putnext(q, mp);
792 }
793 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT, "rlmodwsrv end: q %p, "
794 "mp %p, %s", q, mp, "done");
795 return (0);
796 }
797
798 /*
799 * This routine returns a message block with an expedited
800 * data request
801 */
802 static mblk_t *
803 make_expmblk(char cntl)
804 {
805 mblk_t *mp;
806 mblk_t *bp;
807 struct T_exdata_req *data_req;
808
809 bp = allocb(sizeof (struct T_exdata_req), BPRI_MED);
810 if (bp == NULL)
811 return (NULL);
812 if ((mp = allocb(sizeof (char), BPRI_MED)) == NULL) {
813 freeb(bp);
814 return (NULL);
815 }
816 bp->b_datap->db_type = M_PROTO;
817 data_req = (struct T_exdata_req *)bp->b_rptr;
818 data_req->PRIM_type = T_EXDATA_REQ;
819 data_req->MORE_flag = 0;
820
821 bp->b_wptr += sizeof (struct T_exdata_req);
822 /*
823 * Send a 1 byte data message block with appropriate
824 * control character.
825 */
826 mp->b_datap->db_type = M_DATA;
827 mp->b_wptr = mp->b_rptr + 1;
828 (*(char *)(mp->b_rptr)) = cntl;
829 bp->b_cont = mp;
830 return (bp);
831 }
832 /*
833 * This routine parses M_DATA messages checking for window size protocol
834 * from a given message block. It returns TRUE if no resource exhaustion
835 * conditions are found. This is for use in the service procedure, which
836 * needs to know whether to continue, or stop processing the queue.
837 */
838 static int
839 rlmodrmsg(queue_t *q, mblk_t *mp)
840 {
841 unsigned char *tmp, *tmp1;
842 mblk_t *newmp;
843 size_t sz;
844 ssize_t count, newcount = 0;
845 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
846
847 /*
848 * Eliminate any zero length messages here, so we don't filter EOFs
849 * accidentally.
850 */
851 if (msgdsize(mp) == 0) {
852 ASSERT(rmip->wndw_sz_hd_mp == NULL);
853 goto out;
854 }
855 /*
856 * Check if we have stored a previous message block because a window
857 * update was split over TCP segments. If so, append the new one to
858 * the stored one and process the stored one as if it just arrived.
859 */
860 if (rmip->wndw_sz_hd_mp != NULL) {
861 linkb(rmip->wndw_sz_hd_mp, mp);
862 mp = rmip->wndw_sz_hd_mp;
863 rmip->wndw_sz_hd_mp = NULL;
864 }
865 newmp = mp;
866
867 while (mp) {
868 tmp = mp->b_rptr;
869 /*
870 * scan through the entire message block
871 */
872 while (tmp < mp->b_wptr) {
873 /*
874 * check for FF (rlogin magic escape sequence)
875 */
876 if (tmp[0] == RLOGIN_MAGIC) {
877 /*
878 * Update bytes read so far.
879 */
880 count = newcount + tmp - mp->b_rptr;
881 /*
882 * Pull together message chain in case
883 * window escape is split across blocks.
884 */
885 if ((pullupmsg(newmp, -1)) == 0) {
886 sz = msgdsize(newmp);
887 recover(q, newmp, sz);
888 return (NULL);
889 }
890 /*
891 * pullupmsg results in newmp consuming
892 * all message blocks in this chain, and
893 * therefor mp wants updating.
894 */
895 mp = newmp;
896
897 /*
898 * adjust tmp to where we
899 * stopped - count keeps track
900 * of bytes read so far.
901 * reset newcount = 0.
902 */
903 tmp = mp->b_rptr + count;
904 newcount = 0;
905
906 /*
907 * Use the variable tmp1 to compute where
908 * the end of the window escape (currently
909 * the only rlogin protocol sequence), then
910 * check to see if we got all those bytes.
911 */
912 tmp1 = tmp + 4 + sizeof (struct winsize);
913
914 if (tmp1 > mp->b_wptr) {
915 /*
916 * All the window escape bytes aren't
917 * in this TCP segment. Store this
918 * mblk to one side so we can append
919 * the rest of the escape to it when
920 * its segment arrives.
921 */
922 rmip->wndw_sz_hd_mp = mp;
923 return (TRUE);
924 }
925 /*
926 * check for FF FF s s pattern
927 */
928 if ((tmp[1] == RLOGIN_MAGIC) &&
929 (tmp[2] == 's') && (tmp[3] == 's')) {
930
931 /*
932 * If rlwinsetup returns an error,
933 * we do recover with newmp which
934 * points to new chain of mblks after
935 * doing window control ioctls.
936 * rlwinsetup returns newmp which
937 * contains only data part.
938 * Note that buried inside rlwinsetup
939 * is where we do the putnext.
940 */
941 if (rlwinsetup(q, mp, tmp) == NULL) {
942 sz = msgdsize(mp);
943 recover(q, mp, sz);
944 return (NULL);
945 }
946 /*
947 * We have successfully consumed the
948 * window sequence, but rlwinsetup()
949 * and its children have moved memory
950 * up underneath us. This means that
951 * the byte underneath *tmp has not
952 * been scanned now. We will now need
953 * to rescan it.
954 */
955 continue;
956 }
957 }
958 tmp++;
959 }
960 /*
961 * bump newcount to include size of this particular block.
962 */
963 newcount += (mp->b_wptr - mp->b_rptr);
964 mp = mp->b_cont;
965 }
966 /*
967 * If we trimmed the message down to nothing to forward, don't
968 * send any M_DATA message. (Don't want to send EOF!)
969 */
970 if (msgdsize(newmp) == 0) {
971 freemsg(newmp);
972 newmp = NULL;
973 }
974 out:
975 if (newmp) {
976 if (!canputnext(q)) {
977 (void) putbq(q, newmp);
978 return (NULL);
979 } else {
980 putnext(q, newmp);
981 }
982 }
983 return (TRUE);
984 }
985
986
987 /*
988 * This routine is called to handle window size changes.
989 * The routine returns 1 on success and 0 on error (allocb failure).
990 */
991 static int
992 rlwinctl(queue_t *q, mblk_t *mp)
993 {
994 mblk_t *rl_msgp;
995 struct iocblk *iocbp;
996 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
997
998 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_IN, "rlwinctl start: q %p, "
999 "mp %p", q, mp);
1000
1001 rmip->oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
1002
1003 if ((rl_msgp = mkiocb(TIOCSWINSZ)) == NULL) {
1004 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_OUT, "rlwinctl end: "
1005 "q %p, mp %p, allocb failed", q, mp);
1006 return (0);
1007 }
1008
1009 /*
1010 * create an M_IOCTL message type.
1011 */
1012 rl_msgp->b_cont = mp;
1013 iocbp = (struct iocblk *)rl_msgp->b_rptr;
1014 iocbp->ioc_count = msgdsize(mp);
1015
1016 putnext(q, rl_msgp);
1017 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_OUT, "rlwinctl end: "
1018 "q %p, mp %p, done", q, mp);
1019 return (1);
1020 }
1021
1022 /*
1023 * This routine sets up window size change protocol.
1024 * The routine returns the new mblk after issuing rlwinctl
1025 * for window size changes. New mblk contains only data part
1026 * of the message block. The routine returns 0 on error.
1027 */
1028 static mblk_t *
1029 rlwinsetup(queue_t *q, mblk_t *mp, unsigned char *blk)
1030 {
1031 mblk_t *mp1;
1032 unsigned char *jmpmp;
1033 ssize_t left = 0;
1034 struct winsize win;
1035
1036 /*
1037 * Set jmpmp to where to jump, to get just past the end of the
1038 * window size protocol sequence.
1039 */
1040 jmpmp = (blk + 4 + sizeof (struct winsize));
1041 left = mp->b_wptr - jmpmp;
1042
1043 if ((mp1 = allocb(sizeof (struct winsize), BPRI_MED)) == NULL)
1044 return (0);
1045 mp1->b_datap->db_type = M_DATA;
1046 mp1->b_wptr = mp1->b_rptr + sizeof (struct winsize);
1047 bcopy(blk + 4, &win, sizeof (struct winsize));
1048 win.ws_row = ntohs(win.ws_row);
1049 win.ws_col = ntohs(win.ws_col);
1050 win.ws_xpixel = ntohs(win.ws_xpixel);
1051 win.ws_ypixel = ntohs(win.ws_ypixel);
1052 bcopy(&win, mp1->b_rptr, sizeof (struct winsize));
1053
1054 if ((rlwinctl(q, mp1)) == NULL) {
1055 freeb(mp1);
1056 return (0);
1057 }
1058 if (left > 0) {
1059 /*
1060 * Must delete the window size protocol sequence. We do
1061 * this by sliding all the stuff after the sequence (jmpmp)
1062 * to where the sequence itself began (blk).
1063 */
1064 bcopy(jmpmp, blk, left);
1065 mp->b_wptr = blk + left;
1066 } else
1067 mp->b_wptr = blk;
1068 return (mp);
1069 }
1070
1071 /*
1072 * When an ioctl changes software flow control on the tty, we must notify
1073 * the rlogin client, so it can adjust its behavior appropriately. This
1074 * routine, called from either the put or service routine, determines if
1075 * the flow handling has changed. If so, it tries to send the indication
1076 * to the client. It returns true or false depending upon whether the
1077 * message was fully processed. If it wasn't fully processed it queues
1078 * the message for retry later when resources
1079 * (allocb/canputnext) are available.
1080 */
1081 static boolean_t
1082 tty_flow(queue_t *q, struct rlmod_info *rmip, mblk_t *mp)
1083 {
1084 struct iocblk *ioc;
1085 struct termios *tp;
1086 struct termio *ti;
1087 int stop, ixon;
1088 mblk_t *tmpmp;
1089 char cntl;
1090 int error;
1091
1092 ioc = (struct iocblk *)mp->b_rptr;
1093 switch (ioc->ioc_cmd) {
1094
1095 /*
1096 * If it is a tty ioctl, save the output flow
1097 * control flag and the start and stop flow control
1098 * characters if they are available.
1099 */
1100 case TCSETS:
1101 case TCSETSW:
1102 case TCSETSF:
1103 error = miocpullup(mp, sizeof (struct termios));
1104 if (error != 0) {
1105 miocnak(q, mp, 0, error);
1106 return (B_TRUE);
1107 }
1108 tp = (struct termios *)(mp->b_cont->b_rptr);
1109 rmip->stopc = tp->c_cc[VSTOP];
1110 rmip->startc = tp->c_cc[VSTART];
1111 ixon = tp->c_iflag & IXON;
1112 break;
1113
1114 case TCSETA:
1115 case TCSETAW:
1116 case TCSETAF:
1117 error = miocpullup(mp, sizeof (struct termio));
1118 if (error != 0) {
1119 miocnak(q, mp, 0, error);
1120 return (B_TRUE);
1121 }
1122 ti = (struct termio *)(mp->b_cont->b_rptr);
1123 ixon = ti->c_iflag & IXON;
1124 break;
1125
1126 default:
1127 /*
1128 * This function must never be called for an M_IOCTL
1129 * except the listed ones.
1130 */
1131 #ifdef DEBUG
1132 cmn_err(CE_PANIC,
1133 "rloginmod: tty_flow: bad ioctl 0x%x", ioc->ioc_cmd);
1134 #else
1135 miocnak(q, mp, 0, EINVAL);
1136 return (B_TRUE);
1137 #endif
1138 }
1139 /*
1140 * If tty ioctl processing is done, check for stopmode
1141 */
1142 stop = (ixon && (rmip->stopc == CTRL('s')) &&
1143 (rmip->startc == CTRL('q')));
1144 if (rmip->stopmode == TIOCPKT_NOSTOP) {
1145 if (stop) {
1146 cntl = rmip->oobdata[0] | TIOCPKT_DOSTOP;
1147 if ((tmpmp = make_expmblk(cntl)) == NULL) {
1148 recover(q, mp, sizeof (mblk_t));
1149 return (B_FALSE);
1150 }
1151 if (!canputnext(q)) {
1152 freemsg(tmpmp);
1153 return (B_FALSE);
1154 }
1155 putnext(q, tmpmp);
1156 rmip->stopmode = TIOCPKT_DOSTOP;
1157 }
1158 } else {
1159 if (!stop) {
1160 cntl = rmip->oobdata[0] | TIOCPKT_NOSTOP;
1161 if ((tmpmp = make_expmblk(cntl)) == NULL) {
1162 recover(q, mp, sizeof (mblk_t));
1163 return (B_FALSE);
1164 }
1165 if (!canputnext(q)) {
1166 freemsg(tmpmp);
1167 return (B_FALSE);
1168 }
1169 putnext(q, tmpmp);
1170 rmip->stopmode = TIOCPKT_NOSTOP;
1171 }
1172 }
1173
1174 miocack(q, mp, 0, 0);
1175 return (B_TRUE);
1176 }
1177
1178 /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
1179
1180 static boolean_t
1181 rlmodwioctl(queue_t *q, mblk_t *mp)
1182 {
1183 struct iocblk *ioc;
1184 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1185 int error;
1186
1187 ioc = (struct iocblk *)mp->b_rptr;
1188 switch (ioc->ioc_cmd) {
1189
1190 /*
1191 * This is a special ioctl to reenable the queue.
1192 * The initial data read from the stream head is
1193 * put back on the queue.
1194 */
1195 case RL_IOC_ENABLE:
1196 /*
1197 * Send negative ack if RL_DISABLED flag is not set
1198 */
1199
1200 if (!(rmip->flags & RL_DISABLED)) {
1201 miocnak(q, mp, 0, EINVAL);
1202 break;
1203 }
1204 if (mp->b_cont) {
1205 (void) putbq(RD(q), mp->b_cont);
1206 mp->b_cont = NULL;
1207 }
1208
1209 if (rmip->flags & RL_DISABLED)
1210 rmip->flags &= ~RL_DISABLED;
1211 qenable(RD(q));
1212 miocack(q, mp, 0, 0);
1213 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT,
1214 "rlmodwput end: q %p, mp %p, %s",
1215 q, mp, "IOCACK enable");
1216 return (B_TRUE);
1217
1218 /*
1219 * If it is a tty ioctl, save the output flow
1220 * control flag and the start and stop flow control
1221 * characters if they are available.
1222 */
1223 case TCSETS:
1224 case TCSETSW:
1225 case TCSETSF:
1226 case TCSETA:
1227 case TCSETAW:
1228 case TCSETAF:
1229 return (tty_flow(q, rmip, mp));
1230
1231 #ifdef DEBUG
1232 case TIOCSWINSZ:
1233 case TIOCSTI:
1234 case TCSBRK:
1235 miocnak(q, mp, 0, EINVAL);
1236 break;
1237 #endif
1238 case CRYPTPASSTHRU:
1239 error = miocpullup(mp, sizeof (uchar_t));
1240 if (error != 0) {
1241 miocnak(q, mp, 0, error);
1242 break;
1243 }
1244 if (*(mp->b_cont->b_rptr) == 0x01)
1245 rmip->flags |= RL_IOCPASSTHRU;
1246 else
1247 rmip->flags &= ~RL_IOCPASSTHRU;
1248
1249 miocack(q, mp, NULL, 0);
1250 break;
1251
1252 default:
1253 if (rmip->flags & RL_IOCPASSTHRU) {
1254 putnext(q, mp);
1255 } else {
1256 #ifdef DEBUG
1257 cmn_err(CE_NOTE,
1258 "rlmodwioctl: unexpected ioctl type 0x%x",
1259 ioc->ioc_cmd);
1260 #endif
1261 miocnak(q, mp, 0, EINVAL);
1262 }
1263 }
1264 return (B_TRUE);
1265 }
1266
1267 static void
1268 rlmod_timer(void *arg)
1269 {
1270 queue_t *q = arg;
1271 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1272
1273 ASSERT(rmip);
1274 if (q->q_flag & QREADR) {
1275 ASSERT(rmip->rtimoutid);
1276 rmip->rtimoutid = 0;
1277 } else {
1278 ASSERT(rmip->wtimoutid);
1279 rmip->wtimoutid = 0;
1280 }
1281 enableok(q);
1282 qenable(q);
1283 }
1284
1285 static void
1286 rlmod_buffer(void *arg)
1287 {
1288 queue_t *q = arg;
1289 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1290
1291 ASSERT(rmip);
1292 if (q->q_flag & QREADR) {
1293 ASSERT(rmip->rbufcid);
1294 rmip->rbufcid = 0;
1295 } else {
1296 ASSERT(rmip->wbufcid);
1297 rmip->wbufcid = 0;
1298 }
1299 enableok(q);
1300 qenable(q);
1301 }
1302
1303 static void
1304 recover(queue_t *q, mblk_t *mp, size_t size)
1305 {
1306 /*
1307 * Avoid re-enabling the queue.
1308 */
1309 ASSERT(mp->b_datap->db_type < QPCTL);
1310
1311 noenable(q);
1312 (void) putbq(q, mp);
1313 recover1(q, size);
1314 }
1315
1316 static void
1317 recover1(queue_t *q, size_t size)
1318 {
1319 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1320 timeout_id_t tid;
1321 bufcall_id_t bid;
1322
1323 /*
1324 * Make sure there is at most one outstanding request per queue.
1325 */
1326 if (q->q_flag & QREADR) {
1327 if (rmip->rtimoutid || rmip->rbufcid)
1328 return;
1329 } else {
1330 if (rmip->wtimoutid || rmip->wbufcid)
1331 return;
1332 }
1333 if (!(bid = qbufcall(RD(q), size, BPRI_MED, rlmod_buffer, q))) {
1334 tid = qtimeout(RD(q), rlmod_timer, q, SIMWAIT);
1335 if (q->q_flag & QREADR)
1336 rmip->rtimoutid = tid;
1337 else
1338 rmip->wtimoutid = tid;
1339 } else {
1340 if (q->q_flag & QREADR)
1341 rmip->rbufcid = bid;
1342 else
1343 rmip->wbufcid = bid;
1344 }
1345 }