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