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
  86 _init(void)
  87 {
  88         return (mod_install(&modlinkage));
  89 }
  90 
  91 int
  92 _fini(void)
  93 {
  94         return (mod_remove(&modlinkage));
  95 }
  96 
  97 int
  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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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 *
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
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
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
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
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
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
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 }