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 }