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