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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
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.
38 */
39
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>
61
62 extern struct streamtab rloginmodinfo;
63
64 static struct fmodsw fsw = {
65 "rlmod",
66 &rloginmodinfo,
67 D_MTQPAIR | D_MP
68 };
69
70 /*
71 * Module linkage information for the kernel.
72 */
73
74 static struct modlstrmod modlstrmod = {
75 &mod_strmodops,
76 "rloginmod module",
77 &fsw
78 };
79
80 static struct modlinkage modlinkage = {
81 MODREV_1, &modlstrmod, NULL
82 };
83
84
85 int
_init(void)86 _init(void)
87 {
88 return (mod_install(&modlinkage));
89 }
90
91 int
_fini(void)92 _fini(void)
93 {
94 return (mod_remove(&modlinkage));
95 }
96
97 int
_info(struct modinfo * modinfop)98 _info(struct modinfo *modinfop)
99 {
100 return (mod_info(&modlinkage, modinfop));
101 }
102
103 struct rlmod_info; /* forward reference for function prototype */
104
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 *);
115
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);
122
123 #define RLMOD_ID 106
124 #define SIMWAIT (1*hz)
125
126 /*
127 * Stream module data structure definitions.
128 * generally pushed onto tcp by rlogin daemon
129 *
130 */
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 */
138 };
139
140 static struct qinit rloginmodrinit = {
141 rlmodrput,
142 rlmodrsrv,
143 rlmodopen,
144 rlmodclose,
145 nulldev,
146 &rloginmodiinfo,
147 NULL
148 };
149
150 static struct qinit rloginmodwinit = {
151 rlmodwput,
152 rlmodwsrv,
153 NULL,
154 NULL,
155 nulldev,
156 &rloginmodiinfo,
157 NULL
158 };
159
160 struct streamtab rloginmodinfo = {
161 &rloginmodrinit,
162 &rloginmodwinit,
163 NULL,
164 NULL
165 };
166
167 /*
168 * Per-instance state struct for the rloginmod module.
169 */
170 struct rlmod_info
171 {
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;
184 };
185
186 /*
187 * Flag used in flags
188 */
189 #define RL_DISABLED 0x1
190 #define RL_IOCPASSTHRU 0x2
191
192 /*ARGSUSED*/
193 static void
dummy_callback(void * arg)194 dummy_callback(void *arg)
195 {}
196
197 /*
198 * rlmodopen - open routine gets called when the
199 * module gets pushed onto the stream.
200 */
201 /*ARGSUSED*/
202 static int
rlmodopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * cred)203 rlmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *cred)
204 {
205 struct rlmod_info *rmip;
206 union T_primitives *tp;
207 mblk_t *bp;
208 int error;
209
210 if (sflag != MODOPEN)
211 return (EINVAL);
212
213 if (q->q_ptr != NULL) {
214 /* It's already attached. */
215 return (0);
216 }
217
218 /*
219 * Allocate state structure.
220 */
221 rmip = kmem_zalloc(sizeof (*rmip), KM_SLEEP);
222
223 /*
224 * Cross-link.
225 */
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;
234 /*
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).
237 */
238 rmip->flags |= RL_DISABLED;
239
240 qprocson(q);
241
242 /*
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.
250 */
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;
259 }
260 qunbufcall(q, id);
261 }
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;
267
268 /*
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.
273 */
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;
281 }
282 qunbufcall(q, id);
283 }
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;
289
290 putnext(q, bp);
291 return (0);
292 fail:
293 qprocsoff(q);
294 if (rmip->unbind_mp != NULL) {
295 freemsg(rmip->unbind_mp);
296 }
297 kmem_free(rmip, sizeof (struct rlmod_info));
298 q->q_ptr = NULL;
299 WR(q)->q_ptr = NULL;
300 return (error);
301 }
302
303
304 /*
305 * rlmodclose - This routine gets called when the module
306 * gets popped off of the stream.
307 */
308
309 /*ARGSUSED*/
310 static int
rlmodclose(queue_t * q,int flag,cred_t * credp)311 rlmodclose(queue_t *q, int flag, cred_t *credp)
312 {
313 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
314 mblk_t *mp;
315
316 /*
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.
321 */
322 while (mp = getq(WR(q)))
323 putnext(WR(q), mp);
324
325 /* Poison the stream head so that we can't be pushed again. */
326 (void) putnextctl(q, M_HANGUP);
327
328 qprocsoff(q);
329 if (rmip->wbufcid) {
330 qunbufcall(q, rmip->wbufcid);
331 rmip->wbufcid = 0;
332 }
333 if (rmip->rbufcid) {
334 qunbufcall(q, rmip->rbufcid);
335 rmip->rbufcid = 0;
336 }
337 if (rmip->wtimoutid) {
338 (void) quntimeout(q, rmip->wtimoutid);
339 rmip->wtimoutid = 0;
340 }
341 if (rmip->rtimoutid) {
342 (void) quntimeout(q, rmip->rtimoutid);
343 rmip->rtimoutid = 0;
344 }
345
346 if (rmip->unbind_mp != NULL) {
347 freemsg(rmip->unbind_mp);
348 }
349
350 if (rmip->wndw_sz_hd_mp != NULL) {
351 freemsg(rmip->wndw_sz_hd_mp);
352 }
353
354 kmem_free(q->q_ptr, sizeof (struct rlmod_info));
355 q->q_ptr = WR(q)->q_ptr = NULL;
356 return (0);
357 }
358
359 /*
360 * rlmodrput - Module read queue put procedure.
361 * This is called from the module or
362 * driver downstream.
363 */
364
365 static int
rlmodrput(queue_t * q,mblk_t * mp)366 rlmodrput(queue_t *q, mblk_t *mp)
367 {
368 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
369 union T_primitives *tip;
370
371 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_IN, "rlmodrput start: "
372 "q %p, mp %p", q, mp);
373
374
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);
387 }
388
389 switch (mp->b_datap->db_type) {
390
391 case M_PROTO:
392 case M_PCPROTO:
393 tip = (union T_primitives *)mp->b_rptr;
394 switch (tip->type) {
395
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;
404 }
405 /*
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.
409 */
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);
417 }
418 break;
419
420 /*
421 * We only get T_OK_ACK when we issue the unbind, and it can
422 * be ignored safely.
423 */
424 case T_OK_ACK:
425 ASSERT(rmip->unbind_mp == NULL);
426 freemsg(mp);
427 break;
428
429 default:
430 cmn_err(CE_NOTE,
431 "rlmodrput: got 0x%x type M_PROTO/M_PCPROTO msg",
432 tip->type);
433 freemsg(mp);
434 }
435 break;
436
437 case M_DATA:
438 if (canputnext(q) && q->q_first == NULL) {
439 (void) rlmodrmsg(q, mp);
440 } else {
441 (void) putq(q, mp);
442 }
443 break;
444
445 case M_FLUSH:
446 /*
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.
450 */
451 mp->b_flag |= MSGMARK;
452 if (*mp->b_rptr & FLUSHR)
453 flushq(q, FLUSHALL);
454
455 putnext(q, mp);
456 break;
457
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;
468
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);
475 }
476 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RPUT_OUT, "rlmodrput end: q %p, "
477 "mp %p, %s", q, mp, "done");
478 return (0);
479 }
480
481 /*
482 * rlmodrsrv - module read service procedure
483 */
484 static int
rlmodrsrv(queue_t * q)485 rlmodrsrv(queue_t *q)
486 {
487 mblk_t *mp;
488 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
489 union T_primitives *tip;
490
491 TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_IN, "rlmodrsrv start: "
492 "q %p", q);
493 while ((mp = getq(q)) != NULL) {
494
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);
503 }
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);
510 }
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);
516 }
517 break;
518
519 case M_PROTO:
520 tip = (union T_primitives *)mp->b_rptr;
521 switch (tip->type) {
522
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;
531 }
532 /*
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.
536 */
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);
544 }
545 break;
546
547 /*
548 * We only get T_OK_ACK when we issue the unbind, and
549 * it can be ignored safely.
550 */
551 case T_OK_ACK:
552 ASSERT(rmip->unbind_mp == NULL);
553 freemsg(mp);
554 break;
555
556 default:
557 cmn_err(CE_NOTE,
558 "rlmodrsrv: got 0x%x type PROTO msg",
559 tip->type);
560 freemsg(mp);
561 }
562 break;
563
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);
571 }
572 putnext(q, mp);
573 break;
574
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);
582 }
583 }
584
585 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_RSRV_OUT, "rlmodrsrv end: q %p, "
586 "mp %p, %s", q, mp, "empty");
587
588 return (0);
589 }
590
591 /*
592 * rlmodwput - Module write queue put procedure.
593 * All non-zero messages are send downstream unchanged
594 */
595 static int
rlmodwput(queue_t * q,mblk_t * mp)596 rlmodwput(queue_t *q, mblk_t *mp)
597 {
598 char cntl;
599 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
600 mblk_t *tmpmp;
601 int rw;
602
603 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_IN, "rlmodwput start: "
604 "q %p, mp %p", q, mp);
605
606 if (rmip->rl_expdat) {
607 /*
608 * call make_expmblk to create an expedited
609 * message block.
610 */
611 cntl = rmip->oobdata[0] | TIOCPKT_FLUSHWRITE;
612
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);
619 }
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 */
625 }
626 }
627
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);
633 }
634 switch (mp->b_datap->db_type) {
635
636 case M_DATA:
637 if (!canputnext(q))
638 (void) putq(q, mp);
639 else
640 putnext(q, mp);
641 break;
642
643 case M_FLUSH:
644 /*
645 * We must take care to create and forward out-of-band data
646 * indicating the flush to the far side.
647 */
648 rw = *mp->b_rptr;
649 *mp->b_rptr &= ~FLUSHW;
650 qreply(q, mp);
651 if (rw & FLUSHW) {
652 /*
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.)
657 */
658 flushq(q, FLUSHDATA);
659 /*
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.
668 */
669 (void) putnextctl1(q, M_FLUSH, FLUSHW);
670 /*
671 * Notify peer of the write flush request.
672 */
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);
679 }
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);
687 }
688 putnext(q, mp);
689 }
690 break;
691
692 case M_IOCTL:
693 if (!rlmodwioctl(q, mp))
694 (void) putq(q, mp);
695 break;
696
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;
704
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);
712 }
713 break;
714
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);
722 }
723 break;
724
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;
733 }
734 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WPUT_OUT, "rlmodwput end: "
735 "q %p, mp %p, %s", q, mp, "done");
736 return (0);
737 }
738
739 /*
740 * rlmodwsrv - module write service procedure
741 */
742 static int
rlmodwsrv(queue_t * q)743 rlmodwsrv(queue_t *q)
744 {
745 mblk_t *mp, *tmpmp;
746 char cntl;
747 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
748
749 TRACE_1(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_IN, "rlmodwsrv "
750 "start: q %p", q);
751 if (rmip->rl_expdat) {
752 /*
753 * call make_expmblk to create an expedited
754 * message block.
755 */
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);
762 }
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);
772 }
773 }
774 while ((mp = getq(q)) != NULL) {
775
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);
782 }
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);
790 }
791 continue;
792 }
793 putnext(q, mp);
794 }
795 TRACE_3(TR_FAC_RLOGINP, TR_RLOGINP_WSRV_OUT, "rlmodwsrv end: q %p, "
796 "mp %p, %s", q, mp, "done");
797 return (0);
798 }
799
800 /*
801 * This routine returns a message block with an expedited
802 * data request
803 */
804 static mblk_t *
make_expmblk(char cntl)805 make_expmblk(char cntl)
806 {
807 mblk_t *mp;
808 mblk_t *bp;
809 struct T_exdata_req *data_req;
810
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);
817 }
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;
822
823 bp->b_wptr += sizeof (struct T_exdata_req);
824 /*
825 * Send a 1 byte data message block with appropriate
826 * control character.
827 */
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);
833 }
834 /*
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.
839 */
840 static int
rlmodrmsg(queue_t * q,mblk_t * mp)841 rlmodrmsg(queue_t *q, mblk_t *mp)
842 {
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;
848
849 /*
850 * Eliminate any zero length messages here, so we don't filter EOFs
851 * accidentally.
852 */
853 if (msgdsize(mp) == 0) {
854 ASSERT(rmip->wndw_sz_hd_mp == NULL);
855 goto out;
856 }
857 /*
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.
861 */
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;
866 }
867 newmp = mp;
868
869 while (mp) {
870 tmp = mp->b_rptr;
871 /*
872 * scan through the entire message block
873 */
874 while (tmp < mp->b_wptr) {
875 /*
876 * check for FF (rlogin magic escape sequence)
877 */
878 if (tmp[0] == RLOGIN_MAGIC) {
879 /*
880 * Update bytes read so far.
881 */
882 count = newcount + tmp - mp->b_rptr;
883 /*
884 * Pull together message chain in case
885 * window escape is split across blocks.
886 */
887 if ((pullupmsg(newmp, -1)) == 0) {
888 sz = msgdsize(newmp);
889 recover(q, newmp, sz);
890 return (NULL);
891 }
892 /*
893 * pullupmsg results in newmp consuming
894 * all message blocks in this chain, and
895 * therefor mp wants updating.
896 */
897 mp = newmp;
898
899 /*
900 * adjust tmp to where we
901 * stopped - count keeps track
902 * of bytes read so far.
903 * reset newcount = 0.
904 */
905 tmp = mp->b_rptr + count;
906 newcount = 0;
907
908 /*
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.
913 */
914 tmp1 = tmp + 4 + sizeof (struct winsize);
915
916 if (tmp1 > mp->b_wptr) {
917 /*
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.
923 */
924 rmip->wndw_sz_hd_mp = mp;
925 return (TRUE);
926 }
927 /*
928 * check for FF FF s s pattern
929 */
930 if ((tmp[1] == RLOGIN_MAGIC) &&
931 (tmp[2] == 's') && (tmp[3] == 's')) {
932
933 /*
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.
942 */
943 if (rlwinsetup(q, mp, tmp) == NULL) {
944 sz = msgdsize(mp);
945 recover(q, mp, sz);
946 return (NULL);
947 }
948 /*
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.
956 */
957 continue;
958 }
959 }
960 tmp++;
961 }
962 /*
963 * bump newcount to include size of this particular block.
964 */
965 newcount += (mp->b_wptr - mp->b_rptr);
966 mp = mp->b_cont;
967 }
968 /*
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!)
971 */
972 if (msgdsize(newmp) == 0) {
973 freemsg(newmp);
974 newmp = NULL;
975 }
976 out:
977 if (newmp) {
978 if (!canputnext(q)) {
979 (void) putbq(q, newmp);
980 return (NULL);
981 } else {
982 putnext(q, newmp);
983 }
984 }
985 return (TRUE);
986 }
987
988
989 /*
990 * This routine is called to handle window size changes.
991 * The routine returns 1 on success and 0 on error (allocb failure).
992 */
993 static int
rlwinctl(queue_t * q,mblk_t * mp)994 rlwinctl(queue_t *q, mblk_t *mp)
995 {
996 mblk_t *rl_msgp;
997 struct iocblk *iocbp;
998 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
999
1000 TRACE_2(TR_FAC_RLOGINP, TR_RLOGINP_WINCTL_IN, "rlwinctl start: q %p, "
1001 "mp %p", q, mp);
1002
1003 rmip->oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
1004
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);
1009 }
1010
1011 /*
1012 * create an M_IOCTL message type.
1013 */
1014 rl_msgp->b_cont = mp;
1015 iocbp = (struct iocblk *)rl_msgp->b_rptr;
1016 iocbp->ioc_count = msgdsize(mp);
1017
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);
1022 }
1023
1024 /*
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.
1029 */
1030 static mblk_t *
rlwinsetup(queue_t * q,mblk_t * mp,unsigned char * blk)1031 rlwinsetup(queue_t *q, mblk_t *mp, unsigned char *blk)
1032 {
1033 mblk_t *mp1;
1034 unsigned char *jmpmp;
1035 ssize_t left = 0;
1036 struct winsize win;
1037
1038 /*
1039 * Set jmpmp to where to jump, to get just past the end of the
1040 * window size protocol sequence.
1041 */
1042 jmpmp = (blk + 4 + sizeof (struct winsize));
1043 left = mp->b_wptr - jmpmp;
1044
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));
1055
1056 if ((rlwinctl(q, mp1)) == NULL) {
1057 freeb(mp1);
1058 return (0);
1059 }
1060 if (left > 0) {
1061 /*
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).
1065 */
1066 bcopy(jmpmp, blk, left);
1067 mp->b_wptr = blk + left;
1068 } else
1069 mp->b_wptr = blk;
1070 return (mp);
1071 }
1072
1073 /*
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.
1082 */
1083 static boolean_t
tty_flow(queue_t * q,struct rlmod_info * rmip,mblk_t * mp)1084 tty_flow(queue_t *q, struct rlmod_info *rmip, mblk_t *mp)
1085 {
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;
1093
1094 ioc = (struct iocblk *)mp->b_rptr;
1095 switch (ioc->ioc_cmd) {
1096
1097 /*
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.
1101 */
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);
1109 }
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;
1115
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);
1123 }
1124 ti = (struct termio *)(mp->b_cont->b_rptr);
1125 ixon = ti->c_iflag & IXON;
1126 break;
1127
1128 default:
1129 /*
1130 * This function must never be called for an M_IOCTL
1131 * except the listed ones.
1132 */
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
1140 }
1141 /*
1142 * If tty ioctl processing is done, check for stopmode
1143 */
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);
1152 }
1153 if (!canputnext(q)) {
1154 freemsg(tmpmp);
1155 return (B_FALSE);
1156 }
1157 putnext(q, tmpmp);
1158 rmip->stopmode = TIOCPKT_DOSTOP;
1159 }
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);
1166 }
1167 if (!canputnext(q)) {
1168 freemsg(tmpmp);
1169 return (B_FALSE);
1170 }
1171 putnext(q, tmpmp);
1172 rmip->stopmode = TIOCPKT_NOSTOP;
1173 }
1174 }
1175
1176 miocack(q, mp, 0, 0);
1177 return (B_TRUE);
1178 }
1179
1180 /* rlmodwioctl - handle M_IOCTL messages on the write queue. */
1181
1182 static boolean_t
rlmodwioctl(queue_t * q,mblk_t * mp)1183 rlmodwioctl(queue_t *q, mblk_t *mp)
1184 {
1185 struct iocblk *ioc;
1186 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1187 int error;
1188
1189 ioc = (struct iocblk *)mp->b_rptr;
1190 switch (ioc->ioc_cmd) {
1191
1192 /*
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.
1196 */
1197 case RL_IOC_ENABLE:
1198 /*
1199 * Send negative ack if RL_DISABLED flag is not set
1200 */
1201
1202 if (!(rmip->flags & RL_DISABLED)) {
1203 miocnak(q, mp, 0, EINVAL);
1204 break;
1205 }
1206 if (mp->b_cont) {
1207 (void) putbq(RD(q), mp->b_cont);
1208 mp->b_cont = NULL;
1209 }
1210
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);
1219
1220 /*
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.
1224 */
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));
1232
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;
1245 }
1246 if (*(mp->b_cont->b_rptr) == 0x01)
1247 rmip->flags |= RL_IOCPASSTHRU;
1248 else
1249 rmip->flags &= ~RL_IOCPASSTHRU;
1250
1251 miocack(q, mp, NULL, 0);
1252 break;
1253
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);
1264 }
1265 }
1266 return (B_TRUE);
1267 }
1268
1269 static void
rlmod_timer(void * arg)1270 rlmod_timer(void *arg)
1271 {
1272 queue_t *q = arg;
1273 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1274
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;
1282 }
1283 enableok(q);
1284 qenable(q);
1285 }
1286
1287 static void
rlmod_buffer(void * arg)1288 rlmod_buffer(void *arg)
1289 {
1290 queue_t *q = arg;
1291 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1292
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;
1300 }
1301 enableok(q);
1302 qenable(q);
1303 }
1304
1305 static void
recover(queue_t * q,mblk_t * mp,size_t size)1306 recover(queue_t *q, mblk_t *mp, size_t size)
1307 {
1308 /*
1309 * Avoid re-enabling the queue.
1310 */
1311 ASSERT(mp->b_datap->db_type < QPCTL);
1312
1313 noenable(q);
1314 (void) putbq(q, mp);
1315 recover1(q, size);
1316 }
1317
1318 static void
recover1(queue_t * q,size_t size)1319 recover1(queue_t *q, size_t size)
1320 {
1321 struct rlmod_info *rmip = (struct rlmod_info *)q->q_ptr;
1322 timeout_id_t tid;
1323 bufcall_id_t bid;
1324
1325 /*
1326 * Make sure there is at most one outstanding request per queue.
1327 */
1328 if (q->q_flag & QREADR) {
1329 if (rmip->rtimoutid || rmip->rbufcid)
1330 return;
1331 } else {
1332 if (rmip->wtimoutid || rmip->wbufcid)
1333 return;
1334 }
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;
1346 }
1347 }
1348