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 } 1348