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