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