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 void telmodrput(queue_t *, mblk_t *); 129 static void telmodrsrv(queue_t *); 130 static void telmodwput(queue_t *, mblk_t *); 131 static void 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 (int (*)())telmodrput, 149 (int (*)())telmodrsrv, 150 telmodopen, 151 telmodclose, 152 nulldev, 153 &telmodoinfo, 154 NULL 155 }; 156 157 static struct qinit telmodwinit = { 158 (int (*)())telmodwput, 159 (int (*)())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 void 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; 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; 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 } 502 503 /* 504 * telmodrsrv: 505 * Mostly we end up here because of M_DATA processing delayed due to flow 506 * control or lack of memory. XXX.sparker: TLI primitives here? 507 */ 508 static void 509 telmodrsrv(queue_t *q) 510 { 511 mblk_t *mp, *newmp; 512 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 513 union T_primitives *tip; 514 515 while ((mp = getq(q)) != NULL) { 516 if (((tmip->flags & TEL_STOPPED) && 517 !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) { 518 (void) putbq(q, mp); 519 return; 520 } 521 switch (mp->b_datap->db_type) { 522 523 case M_DATA: 524 is_mdata: 525 if (tmip->flags & TEL_GETBLK) { 526 if ((newmp = allocb(sizeof (char), 527 BPRI_MED)) == NULL) { 528 recover(q, mp, msgdsize(mp)); 529 return; 530 } 531 newmp->b_datap->db_type = M_CTL; 532 newmp->b_wptr = newmp->b_rptr + 1; 533 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 534 newmp->b_cont = mp; 535 tmip->flags &= ~TEL_GETBLK; 536 noenable(q); 537 tmip->flags |= TEL_STOPPED; 538 539 putnext(q, newmp); 540 541 break; 542 } 543 if (!rcv_parse(q, mp)) { 544 return; 545 } 546 break; 547 548 case M_PROTO: 549 550 tip = (union T_primitives *)mp->b_rptr; 551 552 /* 553 * Unless the M_PROTO message indicates data, clear 554 * TEL_GETBLK so that we stop passing our messages 555 * up to the telnet daemon. 556 */ 557 if (tip->type != T_DATA_IND && 558 tip->type != T_EXDATA_IND) 559 tmip->flags &= ~TEL_GETBLK; 560 561 switch (tip->type) { 562 case T_ORDREL_IND: 563 case T_DISCON_IND: 564 /* Make into M_HANGUP and putnext */ 565 ASSERT(mp->b_cont == NULL); 566 mp->b_datap->db_type = M_HANGUP; 567 mp->b_wptr = mp->b_rptr; 568 if (mp->b_cont) { 569 freemsg(mp->b_cont); 570 mp->b_cont = NULL; 571 } 572 /* 573 * If we haven't already, send T_UNBIND_REQ 574 * to prevent TCP from going into "BOUND" 575 * state and locking up the port. 576 */ 577 if (tip->type == T_DISCON_IND && 578 tmip->unbind_mp != NULL) { 579 putnext(q, mp); 580 qreply(q, tmip->unbind_mp); 581 tmip->unbind_mp = NULL; 582 } else { 583 putnext(q, mp); 584 } 585 break; 586 587 case T_DATA_IND: /* conform to TPI, but never happens */ 588 case T_EXDATA_IND: 589 newmp = mp->b_cont; 590 freeb(mp); 591 mp = newmp; 592 if (mp) { 593 ASSERT(mp->b_datap->db_type == M_DATA); 594 if (msgdsize(mp) != 0) { 595 goto is_mdata; 596 } 597 freemsg(mp); 598 } 599 break; 600 601 /* 602 * We only get T_OK_ACK when we issue the unbind, and 603 * it can be ignored safely. 604 */ 605 case T_OK_ACK: 606 ASSERT(tmip->unbind_mp == NULL); 607 freemsg(mp); 608 break; 609 610 default: 611 #ifdef DEBUG 612 cmn_err(CE_NOTE, 613 "telmodrsrv: unexpected TLI primitive " 614 "msg type 0x%x", tip->type); 615 #endif 616 freemsg(mp); 617 } 618 break; 619 620 case M_SETOPTS: 621 putnext(q, mp); 622 break; 623 624 default: 625 #ifdef DEBUG 626 cmn_err(CE_NOTE, 627 "telmodrsrv: unexpected msg type 0x%x", 628 mp->b_datap->db_type); 629 #endif 630 freemsg(mp); 631 } 632 } 633 } 634 635 /* 636 * telmodwput: 637 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon 638 * to process something. M_CTL's are data from the daemon bound for the 639 * network. We forward them immediately. There are two classes of ioctl's 640 * we must handle here also. One is ioctl's forwarded by ptem which we 641 * ignore. The other is ioctl's issued by the daemon to control us. 642 * Process them appropriately. M_PROTO's we pass along, figuring they are 643 * are TPI operations for TCP. M_FLUSH requires careful processing, since 644 * telnet cannot tolerate flushing its protocol requests. Also the flushes 645 * can be running either daemon<->TCP or application<->telmod. We must 646 * carefully deal with this. 647 */ 648 static void 649 telmodwput( 650 queue_t *q, /* Pointer to the read queue */ 651 mblk_t *mp) /* Pointer to current message block */ 652 { 653 struct telmod_info *tmip; 654 struct iocblk *ioc; 655 mblk_t *savemp; 656 int rw; 657 int error; 658 659 tmip = (struct telmod_info *)q->q_ptr; 660 661 switch (mp->b_datap->db_type) { 662 case M_DATA: 663 if (!canputnext(q) || (tmip->flags & TEL_STOPPED) || 664 (q->q_first)) { 665 noenable(q); 666 (void) putq(q, mp); 667 break; 668 } 669 /* 670 * This routine parses data generating from ptm side. 671 * Insert a null character if carraige return 672 * is not followed by line feed unless we are in binary mode. 673 * Also, duplicate IAC if found in the data. 674 */ 675 (void) snd_parse(q, mp); 676 break; 677 678 case M_CTL: 679 if (((mp->b_wptr - mp->b_rptr) == 1) && 680 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) { 681 savemp = mp->b_cont; 682 freeb(mp); 683 mp = savemp; 684 } 685 putnext(q, mp); 686 break; 687 688 case M_IOCTL: 689 ioc = (struct iocblk *)mp->b_rptr; 690 switch (ioc->ioc_cmd) { 691 692 /* 693 * This ioctl is issued by user level daemon to 694 * request one more message block to process protocol 695 */ 696 case TEL_IOC_GETBLK: 697 if (!(tmip->flags & TEL_STOPPED)) { 698 miocnak(q, mp, 0, EINVAL); 699 break; 700 } 701 tmip->flags |= TEL_GETBLK; 702 qenable(RD(q)); 703 enableok(RD(q)); 704 705 miocack(q, mp, 0, 0); 706 break; 707 708 /* 709 * This ioctl is issued by user level daemon to reenable the 710 * read and write queues. This is issued during startup time 711 * after setting up the mux links and also after processing 712 * the protocol. It is also issued after each time an 713 * an unrecognized telnet option is forwarded to the daemon. 714 */ 715 case TEL_IOC_ENABLE: 716 717 /* 718 * Send negative ack if TEL_STOPPED flag is not set 719 */ 720 if (!(tmip->flags & TEL_STOPPED)) { 721 miocnak(q, mp, 0, EINVAL); 722 break; 723 } 724 tmip->flags &= ~TEL_STOPPED; 725 if (mp->b_cont) { 726 (void) putbq(RD(q), mp->b_cont); 727 mp->b_cont = 0; 728 } 729 730 qenable(RD(q)); 731 enableok(RD(q)); 732 qenable(q); 733 enableok(q); 734 735 miocack(q, mp, 0, 0); 736 break; 737 738 /* 739 * Set binary/normal mode for input and output 740 * according to the instructions from the daemon. 741 */ 742 case TEL_IOC_MODE: 743 error = miocpullup(mp, sizeof (uchar_t)); 744 if (error != 0) { 745 miocnak(q, mp, 0, error); 746 break; 747 } 748 tmip->flags |= *(mp->b_cont->b_rptr) & 749 (TEL_BINARY_IN|TEL_BINARY_OUT); 750 miocack(q, mp, 0, 0); 751 break; 752 753 #ifdef DEBUG 754 case TCSETAF: 755 case TCSETSF: 756 case TCSETA: 757 case TCSETAW: 758 case TCSETS: 759 case TCSETSW: 760 case TCSBRK: 761 case TIOCSTI: 762 case TIOCSWINSZ: 763 miocnak(q, mp, 0, EINVAL); 764 break; 765 #endif 766 case CRYPTPASSTHRU: 767 error = miocpullup(mp, sizeof (uchar_t)); 768 if (error != 0) { 769 miocnak(q, mp, 0, error); 770 break; 771 } 772 if (*(mp->b_cont->b_rptr) == 0x01) 773 tmip->flags |= TEL_IOCPASSTHRU; 774 else 775 tmip->flags &= ~TEL_IOCPASSTHRU; 776 777 miocack(q, mp, 0, 0); 778 break; 779 780 default: 781 if (tmip->flags & TEL_IOCPASSTHRU) { 782 putnext(q, mp); 783 } else { 784 #ifdef DEBUG 785 cmn_err(CE_NOTE, 786 "telmodwput: unexpected ioctl type 0x%x", 787 ioc->ioc_cmd); 788 #endif 789 miocnak(q, mp, 0, EINVAL); 790 } 791 break; 792 } 793 break; 794 795 case M_FLUSH: 796 /* 797 * Flushing is tricky: We try to flush all we can, but certain 798 * data cannot be flushed. Telnet protocol sequences cannot 799 * be flushed. So, TCP's queues cannot be flushed since we 800 * cannot tell what might be telnet protocol data. Then we 801 * must take care to create and forward out-of-band data 802 * indicating the flush to the far side. 803 */ 804 rw = *mp->b_rptr; 805 if (rw & FLUSHR) { 806 /* 807 * We cannot flush our read queue, since there may 808 * be telnet protocol bits in the queue, awaiting 809 * processing. However, once it leaves this module 810 * it's guaranteed that all protocol data is in 811 * M_CTL, so we do flush read data beyond us, expecting 812 * them (actually logindmux) to do FLUSHDATAs also. 813 */ 814 *mp->b_rptr = rw & ~FLUSHW; 815 qreply(q, mp); 816 } else { 817 freemsg(mp); 818 } 819 if (rw & FLUSHW) { 820 /* 821 * Since all telnet protocol data comes from the 822 * daemon, stored as M_CTL messages, flushq will 823 * do exactly what's needed: Flush bytes which do 824 * not have telnet protocol data. 825 */ 826 flushq(q, FLUSHDATA); 827 } 828 break; 829 830 case M_PCPROTO: 831 putnext(q, mp); 832 break; 833 834 case M_PROTO: 835 /* We may receive T_DISCON_REQ from the mux */ 836 if (!canputnext(q) || q->q_first != NULL) 837 (void) putq(q, mp); 838 else 839 putnext(q, mp); 840 break; 841 842 default: 843 #ifdef DEBUG 844 cmn_err(CE_NOTE, 845 "telmodwput: unexpected msg type 0x%x", 846 mp->b_datap->db_type); 847 #endif 848 freemsg(mp); 849 break; 850 } 851 } 852 853 /* 854 * telmodwsrv - module write service procedure 855 */ 856 static void 857 telmodwsrv(queue_t *q) 858 { 859 mblk_t *mp, *savemp; 860 861 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 862 863 while ((mp = getq(q)) != NULL) { 864 if (!canputnext(q)) { 865 ASSERT(mp->b_datap->db_type < QPCTL); 866 (void) putbq(q, mp); 867 return; 868 } 869 switch (mp->b_datap->db_type) { 870 871 case M_DATA: 872 if (tmip->flags & TEL_STOPPED) { 873 (void) putbq(q, mp); 874 return; 875 } 876 /* 877 * Insert a null character if carraige return 878 * is not followed by line feed 879 */ 880 if (!snd_parse(q, mp)) { 881 return; 882 } 883 break; 884 885 case M_CTL: 886 if (((mp->b_wptr - mp->b_rptr) == 1) && 887 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) { 888 savemp = mp->b_cont; 889 freeb(mp); 890 mp = savemp; 891 } 892 putnext(q, mp); 893 break; 894 895 case M_PROTO: 896 putnext(q, mp); 897 break; 898 899 default: 900 #ifdef DEBUG 901 cmn_err(CE_NOTE, 902 "telmodwsrv: unexpected msg type 0x%x", 903 mp->b_datap->db_type); 904 #endif 905 freemsg(mp); 906 } 907 908 } 909 } 910 911 /* 912 * This routine is called from read put/service procedure and parses 913 * message block to check for telnet protocol by detecting an IAC. 914 * The routine processes the data part of the message block first and 915 * then sends protocol followed after IAC to the telnet daemon. The 916 * routine also processes CR/LF by eliminating LF/NULL followed after CR. 917 * 918 * Since the code to do this with streams mblks is complicated, some 919 * explanations are in order. If an IAC is found, a dupb() is done, 920 * and the pointers are adjusted to create two streams message. The 921 * (possibly empty) first message contains preceeding data, and the 922 * second begins with the IAC and contains the rest of the streams 923 * message. 924 * 925 * The variables: 926 * datamp: Points to the head of a chain of mblks containing data 927 * which requires no expansion, and can be forwarded directly 928 * to the pty. 929 * prevmp: Points to the last mblk on the datamp chain, used to add 930 * to the chain headed by datamp. 931 * newmp: When an M_CTL header is required, this pointer references 932 * that "header" mblk. 933 * protomp: When an IAC is discovered, a dupb() is done on the first mblk 934 * containing an IAC. protomp points to this dup'ed mblk. 935 * This mblk is eventually forwarded to the daemon. 936 */ 937 static int 938 rcv_parse(queue_t *q, mblk_t *mp) 939 { 940 mblk_t *protomp, *newmp, *datamp, *prevmp; 941 unsigned char *tmp; 942 size_t msgsize; 943 944 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 945 946 datamp = mp; 947 prevmp = protomp = 0; 948 949 while (mp) { 950 /* 951 * If the mblk is empty, just continue scanning. 952 */ 953 if (mp->b_rptr == mp->b_wptr) { 954 prevmp = mp; 955 mp = mp->b_cont; 956 continue; 957 } 958 /* 959 * First check to see if we have received CR and are checking 960 * for a following LF/NULL. If so, do what's necessary to 961 * trim the LF/NULL. This case is for when the LF/NULL is 962 * at the beginning of a subsequent mblk. 963 */ 964 if (!(tmip->flags & TEL_BINARY_IN) && 965 (tmip->flags & TEL_CRRCV)) { 966 if ((*mp->b_rptr == '\n') || (*mp->b_rptr == '\0')) { 967 if (mp->b_wptr == (mp->b_rptr + 1)) { 968 tmip->flags &= ~TEL_CRRCV; 969 if (prevmp) { 970 prevmp->b_cont = mp->b_cont; 971 freeb(mp); 972 mp = prevmp->b_cont; 973 continue; 974 } else { 975 datamp = mp->b_cont; 976 freeb(mp); 977 if (datamp == NULL) { 978 /* 979 * Message contained 980 * only a '\0' after 981 * a '\r' in a previous 982 * message, so we can 983 * read more, even 984 * though we have 985 * nothing to putnext. 986 */ 987 return (1); 988 } else { 989 mp = datamp; 990 continue; 991 } 992 } 993 } 994 mp->b_rptr += 1; 995 } 996 tmip->flags &= ~TEL_CRRCV; 997 } 998 tmp = mp->b_rptr; 999 /* 1000 * Now scan through the entire message block, for IACs 1001 * and CR characters, which need processing. 1002 */ 1003 while (tmp < mp->b_wptr) { 1004 1005 if (tmp[0] == IAC) { 1006 /* 1007 * Telnet protocol - parse it now 1008 * process data part of mblk 1009 * before sending the protocol. 1010 */ 1011 if (tmp > mp->b_rptr) { 1012 if ((protomp = dupb(mp)) == NULL) { 1013 msgsize = msgdsize(datamp); 1014 recover(q, datamp, msgsize); 1015 return (0); 1016 } 1017 ASSERT(tmp >= mp->b_datap->db_base); 1018 ASSERT(tmp <= mp->b_datap->db_lim); 1019 ASSERT(tmp >= 1020 protomp->b_datap->db_base); 1021 ASSERT(tmp <= protomp->b_datap->db_lim); 1022 mp->b_wptr = tmp; 1023 protomp->b_rptr = tmp; 1024 protomp->b_cont = mp->b_cont; 1025 mp->b_cont = 0; 1026 1027 if (prevmp) 1028 prevmp->b_cont = mp; 1029 1030 } else { 1031 protomp = mp; 1032 1033 if (prevmp) 1034 prevmp->b_cont = 0; 1035 else 1036 datamp = 0; 1037 } 1038 if (datamp) { 1039 putnext(q, datamp); 1040 } 1041 /* 1042 * create a 1 byte M_CTL message block with 1043 * protomp and send it down. 1044 */ 1045 1046 if ((newmp = allocb(sizeof (char), 1047 BPRI_MED)) == NULL) { 1048 /* 1049 * Save the dup'ed mp containing 1050 * the protocol information which 1051 * we couldn't get an M_CTL header 1052 * for. 1053 */ 1054 msgsize = msgdsize(protomp); 1055 recover(q, protomp, msgsize); 1056 return (0); 1057 } 1058 newmp->b_datap->db_type = M_CTL; 1059 newmp->b_wptr = newmp->b_rptr + 1; 1060 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 1061 newmp->b_cont = protomp; 1062 noenable(q); 1063 tmip->flags |= TEL_STOPPED; 1064 putnext(q, newmp); 1065 1066 return (0); 1067 } 1068 if (!(tmip->flags & TEL_BINARY_IN)) { 1069 /* 1070 * Set TEL_CRRCV flag if last character is CR 1071 */ 1072 if ((tmp == (mp->b_wptr - 1)) && 1073 (tmp[0] == '\r')) { 1074 tmip->flags |= TEL_CRRCV; 1075 break; 1076 } 1077 1078 /* 1079 * If CR is followed by LF/NULL, get rid of 1080 * LF/NULL and realign the message block. 1081 */ 1082 if ((tmp[0] == '\r') && ((tmp[1] == '\n') || 1083 (tmp[1] == '\0'))) { 1084 /* 1085 * If CR is in the middle of a block, 1086 * we need to get rid of LF and join 1087 * the two pieces together. 1088 */ 1089 if (mp->b_wptr > (tmp + 2)) { 1090 bcopy(tmp + 2, tmp + 1, 1091 (mp->b_wptr - tmp - 2)); 1092 mp->b_wptr -= 1; 1093 } else { 1094 mp->b_wptr = tmp + 1; 1095 } 1096 1097 if (prevmp) 1098 prevmp->b_cont = mp; 1099 } 1100 } 1101 tmp++; 1102 } 1103 prevmp = mp; 1104 mp = mp->b_cont; 1105 } 1106 putnext(q, datamp); 1107 1108 return (1); 1109 } 1110 1111 /* 1112 * This routine is called from write put/service procedures and processes 1113 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are 1114 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk. 1115 * This routine is pessimistic: It pre-allocates a buffer twice the size 1116 * of the incoming message, which is the maximum size a message can become 1117 * after IAC expansion. 1118 * 1119 * savemp: Points at the original message, so it can be freed when 1120 * processing is complete. 1121 * mp: The current point of scanning the message. 1122 * newmp: New message being created with the processed output. 1123 */ 1124 static int 1125 snd_parse(queue_t *q, mblk_t *mp) 1126 { 1127 unsigned char *tmp, *tmp1; 1128 mblk_t *newmp, *savemp; 1129 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1130 size_t size = msgdsize(mp); 1131 1132 savemp = mp; 1133 1134 if (size == 0) { 1135 putnext(q, mp); 1136 return (1); 1137 } 1138 1139 /* 1140 * Extra byte to allocb() takes care of the case when there was 1141 * a '\r' at the end of the previous message and there's a '\r' 1142 * at the beginning of the current message. 1143 */ 1144 if ((newmp = allocb((2 * size)+1, BPRI_MED)) == NULL) { 1145 recover(q, mp, (2 * size)+1); 1146 return (0); 1147 } 1148 newmp->b_datap->db_type = M_DATA; 1149 1150 tmp1 = newmp->b_rptr; 1151 while (mp) { 1152 if (!(tmip->flags & TEL_BINARY_OUT) && 1153 (tmip->flags & TEL_CRSND)) { 1154 if (*(mp->b_rptr) != '\n') 1155 *tmp1++ = '\0'; 1156 tmip->flags &= ~TEL_CRSND; 1157 } 1158 tmp = mp->b_rptr; 1159 while (tmp < mp->b_wptr) { 1160 if (!(tmip->flags & TEL_BINARY_OUT)) { 1161 *tmp1++ = *tmp; 1162 if ((tmp == (mp->b_wptr - 1)) && 1163 (tmp[0] == '\r')) { 1164 tmip->flags |= TEL_CRSND; 1165 break; 1166 } 1167 if ((tmp[0] == '\r') && 1168 (tmp1 == newmp->b_wptr)) { 1169 /* XXX.sparker: can't happen */ 1170 tmip->flags |= TEL_CRSND; 1171 break; 1172 } 1173 if ((tmp[0] == '\r') && (tmp[1] != '\n')) { 1174 *tmp1++ = '\0'; 1175 } 1176 } else 1177 *tmp1++ = *tmp; 1178 1179 if (tmp[0] == IAC) { 1180 *tmp1++ = IAC; 1181 } 1182 tmp++; 1183 } 1184 mp = mp->b_cont; 1185 } 1186 1187 newmp->b_wptr = tmp1; 1188 1189 putnext(q, newmp); 1190 freemsg(savemp); 1191 return (1); 1192 } 1193 1194 static void 1195 telmod_timer(void *arg) 1196 { 1197 queue_t *q = arg; 1198 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1199 1200 ASSERT(tmip); 1201 1202 if (q->q_flag & QREADR) { 1203 ASSERT(tmip->rtimoutid); 1204 tmip->rtimoutid = 0; 1205 } else { 1206 ASSERT(tmip->wtimoutid); 1207 tmip->wtimoutid = 0; 1208 } 1209 enableok(q); 1210 qenable(q); 1211 } 1212 1213 static void 1214 telmod_buffer(void *arg) 1215 { 1216 queue_t *q = arg; 1217 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1218 1219 ASSERT(tmip); 1220 1221 if (q->q_flag & QREADR) { 1222 ASSERT(tmip->rbufcid); 1223 tmip->rbufcid = 0; 1224 } else { 1225 ASSERT(tmip->wbufcid); 1226 tmip->wbufcid = 0; 1227 } 1228 enableok(q); 1229 qenable(q); 1230 } 1231 1232 static void 1233 recover(queue_t *q, mblk_t *mp, size_t size) 1234 { 1235 bufcall_id_t bid; 1236 timeout_id_t tid; 1237 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1238 1239 ASSERT(mp->b_datap->db_type < QPCTL); 1240 noenable(q); 1241 (void) putbq(q, mp); 1242 1243 /* 1244 * Make sure there is at most one outstanding request per queue. 1245 */ 1246 if (q->q_flag & QREADR) { 1247 if (tmip->rtimoutid || tmip->rbufcid) { 1248 return; 1249 } 1250 } else { 1251 if (tmip->wtimoutid || tmip->wbufcid) { 1252 return; 1253 } 1254 } 1255 if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) { 1256 tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT); 1257 if (q->q_flag & QREADR) 1258 tmip->rtimoutid = tid; 1259 else 1260 tmip->wtimoutid = tid; 1261 } else { 1262 if (q->q_flag & QREADR) 1263 tmip->rbufcid = bid; 1264 else 1265 tmip->wbufcid = bid; 1266 } 1267 } 1268