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 "fast path" processing for the telnet protocol. 29 * Since it only knows a very small number of the telnet protocol options, 30 * the daemon is required to assist this module. This module must be run 31 * underneath logindmux, which handles switching messages between the 32 * daemon and the pty master stream appropriately. When an unknown telnet 33 * option is received it is handled as a stop-and-wait operation. The 34 * module refuses to forward data in either direction, and waits for the 35 * daemon to deal with the option, and forward any unprocessed data back 36 * to the daemon. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/stream.h> 42 #include <sys/stropts.h> 43 #include <sys/strsun.h> 44 #include <sys/kmem.h> 45 #include <sys/errno.h> 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/tihdr.h> 49 #include <sys/ptem.h> 50 #include <sys/logindmux.h> 51 #include <sys/telioctl.h> 52 #include <sys/termios.h> 53 #include <sys/debug.h> 54 #include <sys/conf.h> 55 #include <sys/modctl.h> 56 #include <sys/cmn_err.h> 57 #include <sys/cryptmod.h> 58 59 #define IAC 255 60 61 extern struct streamtab telmodinfo; 62 63 #define TELMOD_ID 105 64 #define SIMWAIT (1*hz) 65 66 /* 67 * Module state flags 68 */ 69 #define TEL_IOCPASSTHRU 0x100 70 #define TEL_STOPPED 0x80 71 #define TEL_CRRCV 0x40 72 #define TEL_CRSND 0x20 73 #define TEL_GETBLK 0x10 74 75 /* 76 * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in 77 * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise) 78 * in the module state flag. So those values are not available 79 * even though they are not defined here. 80 */ 81 82 83 84 /* 85 * Per queue instances are single-threaded since the q_ptr 86 * field of queues need to be shared among threads. 87 */ 88 static struct fmodsw fsw = { 89 "telmod", 90 &telmodinfo, 91 D_MTQPAIR | D_MP 92 }; 93 94 /* 95 * Module linkage information for the kernel. 96 */ 97 98 static struct modlstrmod modlstrmod = { 99 &mod_strmodops, 100 "telnet module", 101 &fsw 102 }; 103 104 static struct modlinkage modlinkage = { 105 MODREV_1, &modlstrmod, NULL 106 }; 107 108 int 109 _init() 110 { 111 return (mod_install(&modlinkage)); 112 } 113 114 int 115 _fini() 116 { 117 return (mod_remove(&modlinkage)); 118 } 119 120 int 121 _info(struct modinfo *modinfop) 122 { 123 return (mod_info(&modlinkage, modinfop)); 124 } 125 126 static int telmodopen(queue_t *, dev_t *, int, int, cred_t *); 127 static int telmodclose(queue_t *, int, cred_t *); 128 static int telmodrput(queue_t *, mblk_t *); 129 static int telmodrsrv(queue_t *); 130 static int telmodwput(queue_t *, mblk_t *); 131 static int telmodwsrv(queue_t *); 132 static int rcv_parse(queue_t *q, mblk_t *mp); 133 static int snd_parse(queue_t *q, mblk_t *mp); 134 static void telmod_timer(void *); 135 static void telmod_buffer(void *); 136 static void recover(queue_t *, mblk_t *, size_t); 137 138 static struct module_info telmodoinfo = { 139 TELMOD_ID, /* module id number */ 140 "telmod", /* module name */ 141 0, /* minimum packet size */ 142 INFPSZ, /* maximum packet size */ 143 512, /* hi-water mark */ 144 256 /* lo-water mark */ 145 }; 146 147 static struct qinit telmodrinit = { 148 telmodrput, 149 telmodrsrv, 150 telmodopen, 151 telmodclose, 152 nulldev, 153 &telmodoinfo, 154 NULL 155 }; 156 157 static struct qinit telmodwinit = { 158 telmodwput, 159 telmodwsrv, 160 NULL, 161 NULL, 162 nulldev, 163 &telmodoinfo, 164 NULL 165 }; 166 167 struct streamtab telmodinfo = { 168 &telmodrinit, 169 &telmodwinit, 170 NULL, 171 NULL 172 }; 173 174 /* 175 * Per-instance state struct for the telnet module. 176 */ 177 struct telmod_info { 178 int flags; 179 bufcall_id_t wbufcid; 180 bufcall_id_t rbufcid; 181 timeout_id_t wtimoutid; 182 timeout_id_t rtimoutid; 183 mblk_t *unbind_mp; 184 185 }; 186 187 /*ARGSUSED*/ 188 static void 189 dummy_callback(void *arg) 190 {} 191 192 /* 193 * telmodopen - 194 * A variety of telnet options can never really be processed in the 195 * kernel. For example, TELOPT_TTYPE, must be based in the TERM 196 * environment variable to the login process. Also, data may already 197 * have reached the stream head before telmod was pushed on the stream. 198 * So when telmod is opened, it begins in stopped state, preventing 199 * further data passing either direction through it. It sends a 200 * T_DATA_REQ messages up toward the daemon. This is so the daemon 201 * can be sure that all data which was not processed by telmod 202 * (because it wasn't yet pushed) has been received at the stream head. 203 */ 204 /*ARGSUSED*/ 205 static int 206 telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 207 { 208 struct telmod_info *tmip; 209 mblk_t *bp; 210 union T_primitives *tp; 211 int error; 212 213 if (sflag != MODOPEN) 214 return (EINVAL); 215 216 if (q->q_ptr != NULL) { 217 /* It's already attached. */ 218 return (0); 219 } 220 /* 221 * Allocate state structure. 222 */ 223 tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP); 224 225 /* 226 * Cross-link. 227 */ 228 q->q_ptr = tmip; 229 WR(q)->q_ptr = tmip; 230 231 noenable(q); 232 tmip->flags |= TEL_STOPPED; 233 qprocson(q); 234 235 /* 236 * Since TCP operates in the TLI-inspired brain-dead fashion, 237 * the connection will revert to bound state if the connection 238 * is reset by the client. We must send a T_UNBIND_REQ in 239 * that case so the port doesn't get "wedged" (preventing 240 * inetd from being able to restart the listener). Allocate 241 * it here, so that we don't need to worry about allocb() 242 * failures later. 243 */ 244 while ((tmip->unbind_mp = allocb(sizeof (union T_primitives), 245 BPRI_HI)) == NULL) { 246 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), 247 BPRI_HI, dummy_callback, NULL); 248 if (!qwait_sig(q)) { 249 qunbufcall(q, id); 250 error = EINTR; 251 goto fail; 252 } 253 qunbufcall(q, id); 254 } 255 tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr + 256 sizeof (struct T_unbind_req); 257 tmip->unbind_mp->b_datap->db_type = M_PROTO; 258 tp = (union T_primitives *)tmip->unbind_mp->b_rptr; 259 tp->type = T_UNBIND_REQ; 260 /* 261 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for 262 * read queue since only write queue can get T_DATA_REQ). 263 * Readstream routine in telnet daemon will do a getmsg() till 264 * it receives this proto message 265 */ 266 while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) { 267 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), 268 BPRI_HI, dummy_callback, NULL); 269 if (!qwait_sig(q)) { 270 qunbufcall(q, id); 271 error = EINTR; 272 goto fail; 273 } 274 qunbufcall(q, id); 275 } 276 bp->b_datap->db_type = M_PROTO; 277 bp->b_wptr = bp->b_rptr + sizeof (union T_primitives); 278 tp = (union T_primitives *)bp->b_rptr; 279 tp->type = T_DATA_REQ; 280 tp->data_req.MORE_flag = 0; 281 282 putnext(q, bp); 283 return (0); 284 285 fail: 286 qprocsoff(q); 287 if (tmip->unbind_mp != NULL) { 288 freemsg(tmip->unbind_mp); 289 } 290 kmem_free(tmip, sizeof (struct telmod_info)); 291 q->q_ptr = NULL; 292 WR(q)->q_ptr = NULL; 293 return (error); 294 } 295 296 297 /* 298 * telmodclose - just the normal streams clean-up is required. 299 */ 300 301 /*ARGSUSED*/ 302 static int 303 telmodclose(queue_t *q, int flag, cred_t *credp) 304 { 305 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 306 mblk_t *mp; 307 308 /* 309 * Flush any write-side data downstream. Ignoring flow 310 * control at this point is known to be safe because the 311 * M_HANGUP below poisons the stream such that no modules can 312 * be pushed again. 313 */ 314 while (mp = getq(WR(q))) 315 putnext(WR(q), mp); 316 317 /* Poison the stream head so that we can't be pushed again. */ 318 (void) putnextctl(q, M_HANGUP); 319 320 qprocsoff(q); 321 if (tmip->wbufcid) { 322 qunbufcall(q, tmip->wbufcid); 323 tmip->wbufcid = 0; 324 } 325 if (tmip->rbufcid) { 326 qunbufcall(q, tmip->rbufcid); 327 tmip->rbufcid = 0; 328 } 329 if (tmip->wtimoutid) { 330 (void) quntimeout(q, tmip->wtimoutid); 331 tmip->wtimoutid = 0; 332 } 333 if (tmip->rtimoutid) { 334 (void) quntimeout(q, tmip->rtimoutid); 335 tmip->rtimoutid = 0; 336 } 337 if (tmip->unbind_mp != NULL) { 338 freemsg(tmip->unbind_mp); 339 } 340 341 kmem_free(q->q_ptr, sizeof (struct telmod_info)); 342 q->q_ptr = WR(q)->q_ptr = NULL; 343 return (0); 344 } 345 346 /* 347 * telmodrput: 348 * Be sure to preserve data order. If the daemon is waiting for additional 349 * data (TEL_GETBLK state) forward new data. Otherwise, apply normal 350 * telnet protocol processing to M_DATA. Take notice of TLI messages 351 * indicating connection tear-down, and change them into M_HANGUP's. 352 */ 353 static int 354 telmodrput(queue_t *q, mblk_t *mp) 355 { 356 mblk_t *newmp; 357 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 358 union T_primitives *tip; 359 360 if ((mp->b_datap->db_type < QPCTL) && 361 ((q->q_first) || ((tmip->flags & TEL_STOPPED) && 362 !(tmip->flags & TEL_GETBLK)) || !canputnext(q))) { 363 (void) putq(q, mp); 364 return (0); 365 } 366 367 switch (mp->b_datap->db_type) { 368 case M_DATA: 369 370 /* 371 * If the user level daemon requests for 1 more 372 * block of data (needs more data for protocol processing) 373 * create a M_CTL message block with the mp. 374 */ 375 is_mdata: 376 if (tmip->flags & TEL_GETBLK) { 377 if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) { 378 recover(q, mp, msgdsize(mp)); 379 return (0); 380 } 381 newmp->b_datap->db_type = M_CTL; 382 newmp->b_wptr = newmp->b_rptr + 1; 383 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 384 newmp->b_cont = mp; 385 tmip->flags &= ~TEL_GETBLK; 386 noenable(q); 387 tmip->flags |= TEL_STOPPED; 388 389 putnext(q, newmp); 390 391 break; 392 } 393 /* 394 * call the protocol parsing routine which processes 395 * the data part of the message block first. Then it 396 * handles protocol and CR/LF processing. 397 * If an error is found inside allocb/dupb, recover 398 * routines inside rcv_parse will queue up the 399 * original message block in its service queue. 400 */ 401 (void) rcv_parse(q, mp); 402 break; 403 404 case M_FLUSH: 405 /* 406 * Since M_FLUSH came from TCP, we mark it bound for 407 * daemon, not tty. This only happens when TCP expects 408 * to do a connection reset. 409 */ 410 mp->b_flag |= MSGMARK; 411 if (*mp->b_rptr & FLUSHR) 412 flushq(q, FLUSHALL); 413 putnext(q, mp); 414 break; 415 416 case M_PCSIG: 417 case M_ERROR: 418 if (tmip->flags & TEL_GETBLK) 419 tmip->flags &= ~TEL_GETBLK; 420 /* FALLTHRU */ 421 case M_IOCACK: 422 case M_IOCNAK: 423 case M_SETOPTS: 424 putnext(q, mp); 425 break; 426 427 case M_PROTO: 428 case M_PCPROTO: 429 if (tmip->flags & TEL_GETBLK) 430 tmip->flags &= ~TEL_GETBLK; 431 432 tip = (union T_primitives *)mp->b_rptr; 433 switch (tip->type) { 434 435 case T_ORDREL_IND: 436 case T_DISCON_IND: 437 /* Make into M_HANGUP and putnext */ 438 ASSERT(mp->b_cont == NULL); 439 mp->b_datap->db_type = M_HANGUP; 440 mp->b_wptr = mp->b_rptr; 441 if (mp->b_cont) { 442 freemsg(mp->b_cont); 443 mp->b_cont = NULL; 444 } 445 /* 446 * If we haven't already, send T_UNBIND_REQ to prevent 447 * TCP from going into "BOUND" state and locking up the 448 * port. 449 */ 450 if (tip->type == T_DISCON_IND && tmip->unbind_mp != 451 NULL) { 452 putnext(q, mp); 453 qreply(q, tmip->unbind_mp); 454 tmip->unbind_mp = NULL; 455 } else { 456 putnext(q, mp); 457 } 458 break; 459 460 case T_EXDATA_IND: 461 case T_DATA_IND: /* conform to TPI, but never happens */ 462 newmp = mp->b_cont; 463 freeb(mp); 464 mp = newmp; 465 if (mp) { 466 ASSERT(mp->b_datap->db_type == M_DATA); 467 if (msgdsize(mp) != 0) { 468 goto is_mdata; 469 } 470 freemsg(mp); 471 } 472 break; 473 474 /* 475 * We only get T_OK_ACK when we issue the unbind, and it can 476 * be ignored safely. 477 */ 478 case T_OK_ACK: 479 ASSERT(tmip->unbind_mp == NULL); 480 freemsg(mp); 481 break; 482 483 default: 484 #ifdef DEBUG 485 cmn_err(CE_NOTE, 486 "telmodrput: unexpected TLI primitive msg " 487 "type 0x%x", tip->type); 488 #endif 489 freemsg(mp); 490 } 491 break; 492 493 default: 494 #ifdef DEBUG 495 cmn_err(CE_NOTE, 496 "telmodrput: unexpected msg type 0x%x", 497 mp->b_datap->db_type); 498 #endif 499 freemsg(mp); 500 } 501 return (0); 502 } 503 504 /* 505 * telmodrsrv: 506 * Mostly we end up here because of M_DATA processing delayed due to flow 507 * control or lack of memory. XXX.sparker: TLI primitives here? 508 */ 509 static int 510 telmodrsrv(queue_t *q) 511 { 512 mblk_t *mp, *newmp; 513 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 514 union T_primitives *tip; 515 516 while ((mp = getq(q)) != NULL) { 517 if (((tmip->flags & TEL_STOPPED) && 518 !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) { 519 (void) putbq(q, mp); 520 return (0); 521 } 522 switch (mp->b_datap->db_type) { 523 524 case M_DATA: 525 is_mdata: 526 if (tmip->flags & TEL_GETBLK) { 527 if ((newmp = allocb(sizeof (char), 528 BPRI_MED)) == NULL) { 529 recover(q, mp, msgdsize(mp)); 530 return (0); 531 } 532 newmp->b_datap->db_type = M_CTL; 533 newmp->b_wptr = newmp->b_rptr + 1; 534 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 535 newmp->b_cont = mp; 536 tmip->flags &= ~TEL_GETBLK; 537 noenable(q); 538 tmip->flags |= TEL_STOPPED; 539 540 putnext(q, newmp); 541 542 break; 543 } 544 if (!rcv_parse(q, mp)) { 545 return (0); 546 } 547 break; 548 549 case M_PROTO: 550 551 tip = (union T_primitives *)mp->b_rptr; 552 553 /* 554 * Unless the M_PROTO message indicates data, clear 555 * TEL_GETBLK so that we stop passing our messages 556 * up to the telnet daemon. 557 */ 558 if (tip->type != T_DATA_IND && 559 tip->type != T_EXDATA_IND) 560 tmip->flags &= ~TEL_GETBLK; 561 562 switch (tip->type) { 563 case T_ORDREL_IND: 564 case T_DISCON_IND: 565 /* Make into M_HANGUP and putnext */ 566 ASSERT(mp->b_cont == NULL); 567 mp->b_datap->db_type = M_HANGUP; 568 mp->b_wptr = mp->b_rptr; 569 if (mp->b_cont) { 570 freemsg(mp->b_cont); 571 mp->b_cont = NULL; 572 } 573 /* 574 * If we haven't already, send T_UNBIND_REQ 575 * to prevent TCP from going into "BOUND" 576 * state and locking up the port. 577 */ 578 if (tip->type == T_DISCON_IND && 579 tmip->unbind_mp != NULL) { 580 putnext(q, mp); 581 qreply(q, tmip->unbind_mp); 582 tmip->unbind_mp = NULL; 583 } else { 584 putnext(q, mp); 585 } 586 break; 587 588 case T_DATA_IND: /* conform to TPI, but never happens */ 589 case T_EXDATA_IND: 590 newmp = mp->b_cont; 591 freeb(mp); 592 mp = newmp; 593 if (mp) { 594 ASSERT(mp->b_datap->db_type == M_DATA); 595 if (msgdsize(mp) != 0) { 596 goto is_mdata; 597 } 598 freemsg(mp); 599 } 600 break; 601 602 /* 603 * We only get T_OK_ACK when we issue the unbind, and 604 * it can be ignored safely. 605 */ 606 case T_OK_ACK: 607 ASSERT(tmip->unbind_mp == NULL); 608 freemsg(mp); 609 break; 610 611 default: 612 #ifdef DEBUG 613 cmn_err(CE_NOTE, 614 "telmodrsrv: unexpected TLI primitive " 615 "msg type 0x%x", tip->type); 616 #endif 617 freemsg(mp); 618 } 619 break; 620 621 case M_SETOPTS: 622 putnext(q, mp); 623 break; 624 625 default: 626 #ifdef DEBUG 627 cmn_err(CE_NOTE, 628 "telmodrsrv: unexpected msg type 0x%x", 629 mp->b_datap->db_type); 630 #endif 631 freemsg(mp); 632 } 633 } 634 return (0); 635 } 636 637 /* 638 * telmodwput: 639 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon 640 * to process something. M_CTL's are data from the daemon bound for the 641 * network. We forward them immediately. There are two classes of ioctl's 642 * we must handle here also. One is ioctl's forwarded by ptem which we 643 * ignore. The other is ioctl's issued by the daemon to control us. 644 * Process them appropriately. M_PROTO's we pass along, figuring they are 645 * are TPI operations for TCP. M_FLUSH requires careful processing, since 646 * telnet cannot tolerate flushing its protocol requests. Also the flushes 647 * can be running either daemon<->TCP or application<->telmod. We must 648 * carefully deal with this. 649 */ 650 static int 651 telmodwput( 652 queue_t *q, /* Pointer to the read queue */ 653 mblk_t *mp) /* Pointer to current message block */ 654 { 655 struct telmod_info *tmip; 656 struct iocblk *ioc; 657 mblk_t *savemp; 658 int rw; 659 int error; 660 661 tmip = (struct telmod_info *)q->q_ptr; 662 663 switch (mp->b_datap->db_type) { 664 case M_DATA: 665 if (!canputnext(q) || (tmip->flags & TEL_STOPPED) || 666 (q->q_first)) { 667 noenable(q); 668 (void) putq(q, mp); 669 break; 670 } 671 /* 672 * This routine parses data generating from ptm side. 673 * Insert a null character if carraige return 674 * is not followed by line feed unless we are in binary mode. 675 * Also, duplicate IAC if found in the data. 676 */ 677 (void) snd_parse(q, mp); 678 break; 679 680 case M_CTL: 681 if (((mp->b_wptr - mp->b_rptr) == 1) && 682 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) { 683 savemp = mp->b_cont; 684 freeb(mp); 685 mp = savemp; 686 } 687 putnext(q, mp); 688 break; 689 690 case M_IOCTL: 691 ioc = (struct iocblk *)mp->b_rptr; 692 switch (ioc->ioc_cmd) { 693 694 /* 695 * This ioctl is issued by user level daemon to 696 * request one more message block to process protocol 697 */ 698 case TEL_IOC_GETBLK: 699 if (!(tmip->flags & TEL_STOPPED)) { 700 miocnak(q, mp, 0, EINVAL); 701 break; 702 } 703 tmip->flags |= TEL_GETBLK; 704 qenable(RD(q)); 705 enableok(RD(q)); 706 707 miocack(q, mp, 0, 0); 708 break; 709 710 /* 711 * This ioctl is issued by user level daemon to reenable the 712 * read and write queues. This is issued during startup time 713 * after setting up the mux links and also after processing 714 * the protocol. It is also issued after each time an 715 * an unrecognized telnet option is forwarded to the daemon. 716 */ 717 case TEL_IOC_ENABLE: 718 719 /* 720 * Send negative ack if TEL_STOPPED flag is not set 721 */ 722 if (!(tmip->flags & TEL_STOPPED)) { 723 miocnak(q, mp, 0, EINVAL); 724 break; 725 } 726 tmip->flags &= ~TEL_STOPPED; 727 if (mp->b_cont) { 728 (void) putbq(RD(q), mp->b_cont); 729 mp->b_cont = 0; 730 } 731 732 qenable(RD(q)); 733 enableok(RD(q)); 734 qenable(q); 735 enableok(q); 736 737 miocack(q, mp, 0, 0); 738 break; 739 740 /* 741 * Set binary/normal mode for input and output 742 * according to the instructions from the daemon. 743 */ 744 case TEL_IOC_MODE: 745 error = miocpullup(mp, sizeof (uchar_t)); 746 if (error != 0) { 747 miocnak(q, mp, 0, error); 748 break; 749 } 750 tmip->flags |= *(mp->b_cont->b_rptr) & 751 (TEL_BINARY_IN|TEL_BINARY_OUT); 752 miocack(q, mp, 0, 0); 753 break; 754 755 #ifdef DEBUG 756 case TCSETAF: 757 case TCSETSF: 758 case TCSETA: 759 case TCSETAW: 760 case TCSETS: 761 case TCSETSW: 762 case TCSBRK: 763 case TIOCSTI: 764 case TIOCSWINSZ: 765 miocnak(q, mp, 0, EINVAL); 766 break; 767 #endif 768 case CRYPTPASSTHRU: 769 error = miocpullup(mp, sizeof (uchar_t)); 770 if (error != 0) { 771 miocnak(q, mp, 0, error); 772 break; 773 } 774 if (*(mp->b_cont->b_rptr) == 0x01) 775 tmip->flags |= TEL_IOCPASSTHRU; 776 else 777 tmip->flags &= ~TEL_IOCPASSTHRU; 778 779 miocack(q, mp, 0, 0); 780 break; 781 782 default: 783 if (tmip->flags & TEL_IOCPASSTHRU) { 784 putnext(q, mp); 785 } else { 786 #ifdef DEBUG 787 cmn_err(CE_NOTE, 788 "telmodwput: unexpected ioctl type 0x%x", 789 ioc->ioc_cmd); 790 #endif 791 miocnak(q, mp, 0, EINVAL); 792 } 793 break; 794 } 795 break; 796 797 case M_FLUSH: 798 /* 799 * Flushing is tricky: We try to flush all we can, but certain 800 * data cannot be flushed. Telnet protocol sequences cannot 801 * be flushed. So, TCP's queues cannot be flushed since we 802 * cannot tell what might be telnet protocol data. Then we 803 * must take care to create and forward out-of-band data 804 * indicating the flush to the far side. 805 */ 806 rw = *mp->b_rptr; 807 if (rw & FLUSHR) { 808 /* 809 * We cannot flush our read queue, since there may 810 * be telnet protocol bits in the queue, awaiting 811 * processing. However, once it leaves this module 812 * it's guaranteed that all protocol data is in 813 * M_CTL, so we do flush read data beyond us, expecting 814 * them (actually logindmux) to do FLUSHDATAs also. 815 */ 816 *mp->b_rptr = rw & ~FLUSHW; 817 qreply(q, mp); 818 } else { 819 freemsg(mp); 820 } 821 if (rw & FLUSHW) { 822 /* 823 * Since all telnet protocol data comes from the 824 * daemon, stored as M_CTL messages, flushq will 825 * do exactly what's needed: Flush bytes which do 826 * not have telnet protocol data. 827 */ 828 flushq(q, FLUSHDATA); 829 } 830 break; 831 832 case M_PCPROTO: 833 putnext(q, mp); 834 break; 835 836 case M_PROTO: 837 /* We may receive T_DISCON_REQ from the mux */ 838 if (!canputnext(q) || q->q_first != NULL) 839 (void) putq(q, mp); 840 else 841 putnext(q, mp); 842 break; 843 844 default: 845 #ifdef DEBUG 846 cmn_err(CE_NOTE, 847 "telmodwput: unexpected msg type 0x%x", 848 mp->b_datap->db_type); 849 #endif 850 freemsg(mp); 851 break; 852 } 853 return (0); 854 } 855 856 /* 857 * telmodwsrv - module write service procedure 858 */ 859 static int 860 telmodwsrv(queue_t *q) 861 { 862 mblk_t *mp, *savemp; 863 864 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 865 866 while ((mp = getq(q)) != NULL) { 867 if (!canputnext(q)) { 868 ASSERT(mp->b_datap->db_type < QPCTL); 869 (void) putbq(q, mp); 870 return (0); 871 } 872 switch (mp->b_datap->db_type) { 873 874 case M_DATA: 875 if (tmip->flags & TEL_STOPPED) { 876 (void) putbq(q, mp); 877 return (0); 878 } 879 /* 880 * Insert a null character if carraige return 881 * is not followed by line feed 882 */ 883 if (!snd_parse(q, mp)) { 884 return (0); 885 } 886 break; 887 888 case M_CTL: 889 if (((mp->b_wptr - mp->b_rptr) == 1) && 890 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) { 891 savemp = mp->b_cont; 892 freeb(mp); 893 mp = savemp; 894 } 895 putnext(q, mp); 896 break; 897 898 case M_PROTO: 899 putnext(q, mp); 900 break; 901 902 default: 903 #ifdef DEBUG 904 cmn_err(CE_NOTE, 905 "telmodwsrv: unexpected msg type 0x%x", 906 mp->b_datap->db_type); 907 #endif 908 freemsg(mp); 909 } 910 911 } 912 return (0); 913 } 914 915 /* 916 * This routine is called from read put/service procedure and parses 917 * message block to check for telnet protocol by detecting an IAC. 918 * The routine processes the data part of the message block first and 919 * then sends protocol followed after IAC to the telnet daemon. The 920 * routine also processes CR/LF by eliminating LF/NULL followed after CR. 921 * 922 * Since the code to do this with streams mblks is complicated, some 923 * explanations are in order. If an IAC is found, a dupb() is done, 924 * and the pointers are adjusted to create two streams message. The 925 * (possibly empty) first message contains preceeding data, and the 926 * second begins with the IAC and contains the rest of the streams 927 * message. 928 * 929 * The variables: 930 * datamp: Points to the head of a chain of mblks containing data 931 * which requires no expansion, and can be forwarded directly 932 * to the pty. 933 * prevmp: Points to the last mblk on the datamp chain, used to add 934 * to the chain headed by datamp. 935 * newmp: When an M_CTL header is required, this pointer references 936 * that "header" mblk. 937 * protomp: When an IAC is discovered, a dupb() is done on the first mblk 938 * containing an IAC. protomp points to this dup'ed mblk. 939 * This mblk is eventually forwarded to the daemon. 940 */ 941 static int 942 rcv_parse(queue_t *q, mblk_t *mp) 943 { 944 mblk_t *protomp, *newmp, *datamp, *prevmp; 945 unsigned char *tmp; 946 size_t msgsize; 947 948 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 949 950 datamp = mp; 951 prevmp = protomp = 0; 952 953 while (mp) { 954 /* 955 * If the mblk is empty, just continue scanning. 956 */ 957 if (mp->b_rptr == mp->b_wptr) { 958 prevmp = mp; 959 mp = mp->b_cont; 960 continue; 961 } 962 /* 963 * First check to see if we have received CR and are checking 964 * for a following LF/NULL. If so, do what's necessary to 965 * trim the LF/NULL. This case is for when the LF/NULL is 966 * at the beginning of a subsequent mblk. 967 */ 968 if (!(tmip->flags & TEL_BINARY_IN) && 969 (tmip->flags & TEL_CRRCV)) { 970 if ((*mp->b_rptr == '\n') || (*mp->b_rptr == '\0')) { 971 if (mp->b_wptr == (mp->b_rptr + 1)) { 972 tmip->flags &= ~TEL_CRRCV; 973 if (prevmp) { 974 prevmp->b_cont = mp->b_cont; 975 freeb(mp); 976 mp = prevmp->b_cont; 977 continue; 978 } else { 979 datamp = mp->b_cont; 980 freeb(mp); 981 if (datamp == NULL) { 982 /* 983 * Message contained 984 * only a '\0' after 985 * a '\r' in a previous 986 * message, so we can 987 * read more, even 988 * though we have 989 * nothing to putnext. 990 */ 991 return (1); 992 } else { 993 mp = datamp; 994 continue; 995 } 996 } 997 } 998 mp->b_rptr += 1; 999 } 1000 tmip->flags &= ~TEL_CRRCV; 1001 } 1002 tmp = mp->b_rptr; 1003 /* 1004 * Now scan through the entire message block, for IACs 1005 * and CR characters, which need processing. 1006 */ 1007 while (tmp < mp->b_wptr) { 1008 1009 if (tmp[0] == IAC) { 1010 /* 1011 * Telnet protocol - parse it now 1012 * process data part of mblk 1013 * before sending the protocol. 1014 */ 1015 if (tmp > mp->b_rptr) { 1016 if ((protomp = dupb(mp)) == NULL) { 1017 msgsize = msgdsize(datamp); 1018 recover(q, datamp, msgsize); 1019 return (0); 1020 } 1021 ASSERT(tmp >= mp->b_datap->db_base); 1022 ASSERT(tmp <= mp->b_datap->db_lim); 1023 ASSERT(tmp >= 1024 protomp->b_datap->db_base); 1025 ASSERT(tmp <= protomp->b_datap->db_lim); 1026 mp->b_wptr = tmp; 1027 protomp->b_rptr = tmp; 1028 protomp->b_cont = mp->b_cont; 1029 mp->b_cont = 0; 1030 1031 if (prevmp) 1032 prevmp->b_cont = mp; 1033 1034 } else { 1035 protomp = mp; 1036 1037 if (prevmp) 1038 prevmp->b_cont = 0; 1039 else 1040 datamp = 0; 1041 } 1042 if (datamp) { 1043 putnext(q, datamp); 1044 } 1045 /* 1046 * create a 1 byte M_CTL message block with 1047 * protomp and send it down. 1048 */ 1049 1050 if ((newmp = allocb(sizeof (char), 1051 BPRI_MED)) == NULL) { 1052 /* 1053 * Save the dup'ed mp containing 1054 * the protocol information which 1055 * we couldn't get an M_CTL header 1056 * for. 1057 */ 1058 msgsize = msgdsize(protomp); 1059 recover(q, protomp, msgsize); 1060 return (0); 1061 } 1062 newmp->b_datap->db_type = M_CTL; 1063 newmp->b_wptr = newmp->b_rptr + 1; 1064 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 1065 newmp->b_cont = protomp; 1066 noenable(q); 1067 tmip->flags |= TEL_STOPPED; 1068 putnext(q, newmp); 1069 1070 return (0); 1071 } 1072 if (!(tmip->flags & TEL_BINARY_IN)) { 1073 /* 1074 * Set TEL_CRRCV flag if last character is CR 1075 */ 1076 if ((tmp == (mp->b_wptr - 1)) && 1077 (tmp[0] == '\r')) { 1078 tmip->flags |= TEL_CRRCV; 1079 break; 1080 } 1081 1082 /* 1083 * If CR is followed by LF/NULL, get rid of 1084 * LF/NULL and realign the message block. 1085 */ 1086 if ((tmp[0] == '\r') && ((tmp[1] == '\n') || 1087 (tmp[1] == '\0'))) { 1088 /* 1089 * If CR is in the middle of a block, 1090 * we need to get rid of LF and join 1091 * the two pieces together. 1092 */ 1093 if (mp->b_wptr > (tmp + 2)) { 1094 bcopy(tmp + 2, tmp + 1, 1095 (mp->b_wptr - tmp - 2)); 1096 mp->b_wptr -= 1; 1097 } else { 1098 mp->b_wptr = tmp + 1; 1099 } 1100 1101 if (prevmp) 1102 prevmp->b_cont = mp; 1103 } 1104 } 1105 tmp++; 1106 } 1107 prevmp = mp; 1108 mp = mp->b_cont; 1109 } 1110 putnext(q, datamp); 1111 1112 return (1); 1113 } 1114 1115 /* 1116 * This routine is called from write put/service procedures and processes 1117 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are 1118 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk. 1119 * This routine is pessimistic: It pre-allocates a buffer twice the size 1120 * of the incoming message, which is the maximum size a message can become 1121 * after IAC expansion. 1122 * 1123 * savemp: Points at the original message, so it can be freed when 1124 * processing is complete. 1125 * mp: The current point of scanning the message. 1126 * newmp: New message being created with the processed output. 1127 */ 1128 static int 1129 snd_parse(queue_t *q, mblk_t *mp) 1130 { 1131 unsigned char *tmp, *tmp1; 1132 mblk_t *newmp, *savemp; 1133 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1134 size_t size = msgdsize(mp); 1135 1136 savemp = mp; 1137 1138 if (size == 0) { 1139 putnext(q, mp); 1140 return (1); 1141 } 1142 1143 /* 1144 * Extra byte to allocb() takes care of the case when there was 1145 * a '\r' at the end of the previous message and there's a '\r' 1146 * at the beginning of the current message. 1147 */ 1148 if ((newmp = allocb((2 * size)+1, BPRI_MED)) == NULL) { 1149 recover(q, mp, (2 * size)+1); 1150 return (0); 1151 } 1152 newmp->b_datap->db_type = M_DATA; 1153 1154 tmp1 = newmp->b_rptr; 1155 while (mp) { 1156 if (!(tmip->flags & TEL_BINARY_OUT) && 1157 (tmip->flags & TEL_CRSND)) { 1158 if (*(mp->b_rptr) != '\n') 1159 *tmp1++ = '\0'; 1160 tmip->flags &= ~TEL_CRSND; 1161 } 1162 tmp = mp->b_rptr; 1163 while (tmp < mp->b_wptr) { 1164 if (!(tmip->flags & TEL_BINARY_OUT)) { 1165 *tmp1++ = *tmp; 1166 if ((tmp == (mp->b_wptr - 1)) && 1167 (tmp[0] == '\r')) { 1168 tmip->flags |= TEL_CRSND; 1169 break; 1170 } 1171 if ((tmp[0] == '\r') && 1172 (tmp1 == newmp->b_wptr)) { 1173 /* XXX.sparker: can't happen */ 1174 tmip->flags |= TEL_CRSND; 1175 break; 1176 } 1177 if ((tmp[0] == '\r') && (tmp[1] != '\n')) { 1178 *tmp1++ = '\0'; 1179 } 1180 } else 1181 *tmp1++ = *tmp; 1182 1183 if (tmp[0] == IAC) { 1184 *tmp1++ = IAC; 1185 } 1186 tmp++; 1187 } 1188 mp = mp->b_cont; 1189 } 1190 1191 newmp->b_wptr = tmp1; 1192 1193 putnext(q, newmp); 1194 freemsg(savemp); 1195 return (1); 1196 } 1197 1198 static void 1199 telmod_timer(void *arg) 1200 { 1201 queue_t *q = arg; 1202 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1203 1204 ASSERT(tmip); 1205 1206 if (q->q_flag & QREADR) { 1207 ASSERT(tmip->rtimoutid); 1208 tmip->rtimoutid = 0; 1209 } else { 1210 ASSERT(tmip->wtimoutid); 1211 tmip->wtimoutid = 0; 1212 } 1213 enableok(q); 1214 qenable(q); 1215 } 1216 1217 static void 1218 telmod_buffer(void *arg) 1219 { 1220 queue_t *q = arg; 1221 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1222 1223 ASSERT(tmip); 1224 1225 if (q->q_flag & QREADR) { 1226 ASSERT(tmip->rbufcid); 1227 tmip->rbufcid = 0; 1228 } else { 1229 ASSERT(tmip->wbufcid); 1230 tmip->wbufcid = 0; 1231 } 1232 enableok(q); 1233 qenable(q); 1234 } 1235 1236 static void 1237 recover(queue_t *q, mblk_t *mp, size_t size) 1238 { 1239 bufcall_id_t bid; 1240 timeout_id_t tid; 1241 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1242 1243 ASSERT(mp->b_datap->db_type < QPCTL); 1244 noenable(q); 1245 (void) putbq(q, mp); 1246 1247 /* 1248 * Make sure there is at most one outstanding request per queue. 1249 */ 1250 if (q->q_flag & QREADR) { 1251 if (tmip->rtimoutid || tmip->rbufcid) { 1252 return; 1253 } 1254 } else { 1255 if (tmip->wtimoutid || tmip->wbufcid) { 1256 return; 1257 } 1258 } 1259 if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) { 1260 tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT); 1261 if (q->q_flag & QREADR) 1262 tmip->rtimoutid = tid; 1263 else 1264 tmip->wtimoutid = tid; 1265 } else { 1266 if (q->q_flag & QREADR) 1267 tmip->rbufcid = bid; 1268 else 1269 tmip->wbufcid = bid; 1270 } 1271 } 1272