1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module implements the "fast path" processing for the telnet protocol. 31 * Since it only knows a very small number of the telnet protocol options, 32 * the daemon is required to assist this module. This module must be run 33 * underneath logindmux, which handles switching messages between the 34 * daemon and the pty master stream appropriately. When an unknown telnet 35 * option is received it is handled as a stop-and-wait operation. The 36 * module refuses to forward data in either direction, and waits for the 37 * daemon to deal with the option, and forward any unprocessed data back 38 * to the daemon. 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/logindmux.h> 53 #include <sys/telioctl.h> 54 #include <sys/termios.h> 55 #include <sys/debug.h> 56 #include <sys/conf.h> 57 #include <sys/modctl.h> 58 #include <sys/cmn_err.h> 59 #include <sys/cryptmod.h> 60 61 #define IAC 255 62 63 extern struct streamtab telmodinfo; 64 65 #define TELMOD_ID 105 66 #define SIMWAIT (1*hz) 67 68 /* 69 * Module state flags 70 */ 71 #define TEL_IOCPASSTHRU 0x100 72 #define TEL_STOPPED 0x80 73 #define TEL_CRRCV 0x40 74 #define TEL_CRSND 0x20 75 #define TEL_GETBLK 0x10 76 77 /* 78 * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in 79 * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise) 80 * in the module state flag. So those values are not available 81 * even though they are not defined here. 82 */ 83 84 85 86 /* 87 * Per queue instances are single-threaded since the q_ptr 88 * field of queues need to be shared among threads. 89 */ 90 static struct fmodsw fsw = { 91 "telmod", 92 &telmodinfo, 93 D_MTQPAIR | D_MP 94 }; 95 96 /* 97 * Module linkage information for the kernel. 98 */ 99 100 static struct modlstrmod modlstrmod = { 101 &mod_strmodops, 102 "telnet module", 103 &fsw 104 }; 105 106 static struct modlinkage modlinkage = { 107 MODREV_1, &modlstrmod, NULL 108 }; 109 110 int 111 _init() 112 { 113 return (mod_install(&modlinkage)); 114 } 115 116 int 117 _fini() 118 { 119 return (mod_remove(&modlinkage)); 120 } 121 122 int 123 _info(struct modinfo *modinfop) 124 { 125 return (mod_info(&modlinkage, modinfop)); 126 } 127 128 static int telmodopen(queue_t *, dev_t *, int, int, cred_t *); 129 static int telmodclose(queue_t *, int, cred_t *); 130 static void telmodrput(queue_t *, mblk_t *); 131 static void telmodrsrv(queue_t *); 132 static void telmodwput(queue_t *, mblk_t *); 133 static void telmodwsrv(queue_t *); 134 static int rcv_parse(queue_t *q, mblk_t *mp); 135 static int snd_parse(queue_t *q, mblk_t *mp); 136 static void telmod_timer(void *); 137 static void telmod_buffer(void *); 138 static void recover(queue_t *, mblk_t *, size_t); 139 140 static struct module_info telmodoinfo = { 141 TELMOD_ID, /* module id number */ 142 "telmod", /* module name */ 143 0, /* minimum packet size */ 144 INFPSZ, /* maximum packet size */ 145 512, /* hi-water mark */ 146 256 /* lo-water mark */ 147 }; 148 149 static struct qinit telmodrinit = { 150 (int (*)())telmodrput, 151 (int (*)())telmodrsrv, 152 telmodopen, 153 telmodclose, 154 nulldev, 155 &telmodoinfo, 156 NULL 157 }; 158 159 static struct qinit telmodwinit = { 160 (int (*)())telmodwput, 161 (int (*)())telmodwsrv, 162 NULL, 163 NULL, 164 nulldev, 165 &telmodoinfo, 166 NULL 167 }; 168 169 struct streamtab telmodinfo = { 170 &telmodrinit, 171 &telmodwinit, 172 NULL, 173 NULL 174 }; 175 176 /* 177 * Per-instance state struct for the telnet module. 178 */ 179 struct telmod_info { 180 int flags; 181 bufcall_id_t wbufcid; 182 bufcall_id_t rbufcid; 183 timeout_id_t wtimoutid; 184 timeout_id_t rtimoutid; 185 mblk_t *unbind_mp; 186 187 }; 188 189 /*ARGSUSED*/ 190 static void 191 dummy_callback(void *arg) 192 {} 193 194 /* 195 * telmodopen - 196 * A variety of telnet options can never really be processed in the 197 * kernel. For example, TELOPT_TTYPE, must be based in the TERM 198 * environment variable to the login process. Also, data may already 199 * have reached the stream head before telmod was pushed on the stream. 200 * So when telmod is opened, it begins in stopped state, preventing 201 * further data passing either direction through it. It sends a 202 * T_DATA_REQ messages up toward the daemon. This is so the daemon 203 * can be sure that all data which was not processed by telmod 204 * (because it wasn't yet pushed) has been received at the stream head. 205 */ 206 /*ARGSUSED*/ 207 static int 208 telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) 209 { 210 struct telmod_info *tmip; 211 mblk_t *bp; 212 union T_primitives *tp; 213 int error; 214 215 if (sflag != MODOPEN) 216 return (EINVAL); 217 218 if (q->q_ptr != NULL) { 219 /* It's already attached. */ 220 return (0); 221 } 222 /* 223 * Allocate state structure. 224 */ 225 tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP); 226 227 /* 228 * Cross-link. 229 */ 230 q->q_ptr = tmip; 231 WR(q)->q_ptr = tmip; 232 233 noenable(q); 234 tmip->flags |= TEL_STOPPED; 235 qprocson(q); 236 237 /* 238 * Since TCP operates in the TLI-inspired brain-dead fashion, 239 * the connection will revert to bound state if the connection 240 * is reset by the client. We must send a T_UNBIND_REQ in 241 * that case so the port doesn't get "wedged" (preventing 242 * inetd from being able to restart the listener). Allocate 243 * it here, so that we don't need to worry about allocb() 244 * failures later. 245 */ 246 while ((tmip->unbind_mp = allocb(sizeof (union T_primitives), 247 BPRI_HI)) == NULL) { 248 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), 249 BPRI_HI, dummy_callback, NULL); 250 if (!qwait_sig(q)) { 251 qunbufcall(q, id); 252 error = EINTR; 253 goto fail; 254 } 255 qunbufcall(q, id); 256 } 257 tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr + 258 sizeof (struct T_unbind_req); 259 tmip->unbind_mp->b_datap->db_type = M_PROTO; 260 tp = (union T_primitives *)tmip->unbind_mp->b_rptr; 261 tp->type = T_UNBIND_REQ; 262 /* 263 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for 264 * read queue since only write queue can get T_DATA_REQ). 265 * Readstream routine in telnet daemon will do a getmsg() till 266 * it receives this proto message 267 */ 268 while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) { 269 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), 270 BPRI_HI, dummy_callback, NULL); 271 if (!qwait_sig(q)) { 272 qunbufcall(q, id); 273 error = EINTR; 274 goto fail; 275 } 276 qunbufcall(q, id); 277 } 278 bp->b_datap->db_type = M_PROTO; 279 bp->b_wptr = bp->b_rptr + sizeof (union T_primitives); 280 tp = (union T_primitives *)bp->b_rptr; 281 tp->type = T_DATA_REQ; 282 tp->data_req.MORE_flag = 0; 283 284 putnext(q, bp); 285 return (0); 286 287 fail: 288 qprocsoff(q); 289 if (tmip->unbind_mp != NULL) { 290 freemsg(tmip->unbind_mp); 291 } 292 kmem_free(tmip, sizeof (struct telmod_info)); 293 q->q_ptr = NULL; 294 WR(q)->q_ptr = NULL; 295 return (error); 296 } 297 298 299 /* 300 * telmodclose - just the normal streams clean-up is required. 301 */ 302 303 /*ARGSUSED*/ 304 static int 305 telmodclose(queue_t *q, int flag, cred_t *credp) 306 { 307 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 308 mblk_t *mp; 309 310 /* 311 * Flush any write-side data downstream. Ignoring flow 312 * control at this point is known to be safe because the 313 * M_HANGUP below poisons the stream such that no modules can 314 * be pushed again. 315 */ 316 while (mp = getq(WR(q))) 317 putnext(WR(q), mp); 318 319 /* Poison the stream head so that we can't be pushed again. */ 320 (void) putnextctl(q, M_HANGUP); 321 322 qprocsoff(q); 323 if (tmip->wbufcid) { 324 qunbufcall(q, tmip->wbufcid); 325 tmip->wbufcid = 0; 326 } 327 if (tmip->rbufcid) { 328 qunbufcall(q, tmip->rbufcid); 329 tmip->rbufcid = 0; 330 } 331 if (tmip->wtimoutid) { 332 (void) quntimeout(q, tmip->wtimoutid); 333 tmip->wtimoutid = 0; 334 } 335 if (tmip->rtimoutid) { 336 (void) quntimeout(q, tmip->rtimoutid); 337 tmip->rtimoutid = 0; 338 } 339 if (tmip->unbind_mp != NULL) { 340 freemsg(tmip->unbind_mp); 341 } 342 343 kmem_free(q->q_ptr, sizeof (struct telmod_info)); 344 q->q_ptr = WR(q)->q_ptr = NULL; 345 return (0); 346 } 347 348 /* 349 * telmodrput: 350 * Be sure to preserve data order. If the daemon is waiting for additional 351 * data (TEL_GETBLK state) forward new data. Otherwise, apply normal 352 * telnet protocol processing to M_DATA. Take notice of TLI messages 353 * indicating connection tear-down, and change them into M_HANGUP's. 354 */ 355 static void 356 telmodrput(queue_t *q, mblk_t *mp) 357 { 358 mblk_t *newmp; 359 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 360 union T_primitives *tip; 361 362 if ((mp->b_datap->db_type < QPCTL) && 363 ((q->q_first) || ((tmip->flags & TEL_STOPPED) && 364 !(tmip->flags & TEL_GETBLK)) || !canputnext(q))) { 365 (void) putq(q, mp); 366 return; 367 } 368 369 switch (mp->b_datap->db_type) { 370 case M_DATA: 371 372 /* 373 * If the user level daemon requests for 1 more 374 * block of data (needs more data for protocol processing) 375 * create a M_CTL message block with the mp. 376 */ 377 is_mdata: 378 if (tmip->flags & TEL_GETBLK) { 379 if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) { 380 recover(q, mp, msgdsize(mp)); 381 return; 382 } 383 newmp->b_datap->db_type = M_CTL; 384 newmp->b_wptr = newmp->b_rptr + 1; 385 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 386 newmp->b_cont = mp; 387 tmip->flags &= ~TEL_GETBLK; 388 noenable(q); 389 tmip->flags |= TEL_STOPPED; 390 391 putnext(q, newmp); 392 393 break; 394 } 395 /* 396 * call the protocol parsing routine which processes 397 * the data part of the message block first. Then it 398 * handles protocol and CR/LF processing. 399 * If an error is found inside allocb/dupb, recover 400 * routines inside rcv_parse will queue up the 401 * original message block in its service queue. 402 */ 403 (void) rcv_parse(q, mp); 404 break; 405 406 case M_FLUSH: 407 /* 408 * Since M_FLUSH came from TCP, we mark it bound for 409 * daemon, not tty. This only happens when TCP expects 410 * to do a connection reset. 411 */ 412 mp->b_flag |= MSGMARK; 413 if (*mp->b_rptr & FLUSHR) 414 flushq(q, FLUSHALL); 415 putnext(q, mp); 416 break; 417 418 case M_PCSIG: 419 case M_ERROR: 420 if (tmip->flags & TEL_GETBLK) 421 tmip->flags &= ~TEL_GETBLK; 422 /* FALLTHRU */ 423 case M_IOCACK: 424 case M_IOCNAK: 425 case M_SETOPTS: 426 putnext(q, mp); 427 break; 428 429 case M_PROTO: 430 case M_PCPROTO: 431 if (tmip->flags & TEL_GETBLK) 432 tmip->flags &= ~TEL_GETBLK; 433 434 tip = (union T_primitives *)mp->b_rptr; 435 switch (tip->type) { 436 437 case T_ORDREL_IND: 438 case T_DISCON_IND: 439 /* Make into M_HANGUP and putnext */ 440 ASSERT(mp->b_cont == NULL); 441 mp->b_datap->db_type = M_HANGUP; 442 mp->b_wptr = mp->b_rptr; 443 if (mp->b_cont) { 444 freemsg(mp->b_cont); 445 mp->b_cont = NULL; 446 } 447 /* 448 * If we haven't already, send T_UNBIND_REQ to prevent 449 * TCP from going into "BOUND" state and locking up the 450 * port. 451 */ 452 if (tip->type == T_DISCON_IND && tmip->unbind_mp != 453 NULL) { 454 putnext(q, mp); 455 qreply(q, tmip->unbind_mp); 456 tmip->unbind_mp = NULL; 457 } else { 458 putnext(q, mp); 459 } 460 break; 461 462 case T_EXDATA_IND: 463 case T_DATA_IND: /* conform to TPI, but never happens */ 464 newmp = mp->b_cont; 465 freeb(mp); 466 mp = newmp; 467 if (mp) { 468 ASSERT(mp->b_datap->db_type == M_DATA); 469 if (msgdsize(mp) != 0) { 470 goto is_mdata; 471 } 472 freemsg(mp); 473 } 474 break; 475 476 /* 477 * We only get T_OK_ACK when we issue the unbind, and it can 478 * be ignored safely. 479 */ 480 case T_OK_ACK: 481 ASSERT(tmip->unbind_mp == NULL); 482 freemsg(mp); 483 break; 484 485 default: 486 #ifdef DEBUG 487 cmn_err(CE_NOTE, 488 "telmodrput: unexpected TLI primitive msg " 489 "type 0x%x", tip->type); 490 #endif 491 freemsg(mp); 492 } 493 break; 494 495 default: 496 #ifdef DEBUG 497 cmn_err(CE_NOTE, 498 "telmodrput: unexpected msg type 0x%x", 499 mp->b_datap->db_type); 500 #endif 501 freemsg(mp); 502 } 503 } 504 505 /* 506 * telmodrsrv: 507 * Mostly we end up here because of M_DATA processing delayed due to flow 508 * control or lack of memory. XXX.sparker: TLI primitives here? 509 */ 510 static void 511 telmodrsrv(queue_t *q) 512 { 513 mblk_t *mp, *newmp; 514 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 515 union T_primitives *tip; 516 517 while ((mp = getq(q)) != NULL) { 518 if (((tmip->flags & TEL_STOPPED) && 519 !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) { 520 (void) putbq(q, mp); 521 return; 522 } 523 switch (mp->b_datap->db_type) { 524 525 case M_DATA: 526 is_mdata: 527 if (tmip->flags & TEL_GETBLK) { 528 if ((newmp = allocb(sizeof (char), 529 BPRI_MED)) == NULL) { 530 recover(q, mp, msgdsize(mp)); 531 return; 532 } 533 newmp->b_datap->db_type = M_CTL; 534 newmp->b_wptr = newmp->b_rptr + 1; 535 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 536 newmp->b_cont = mp; 537 tmip->flags &= ~TEL_GETBLK; 538 noenable(q); 539 tmip->flags |= TEL_STOPPED; 540 541 putnext(q, newmp); 542 543 break; 544 } 545 if (!rcv_parse(q, mp)) { 546 return; 547 } 548 break; 549 550 case M_PROTO: 551 552 tip = (union T_primitives *)mp->b_rptr; 553 554 /* 555 * Unless the M_PROTO message indicates data, clear 556 * TEL_GETBLK so that we stop passing our messages 557 * up to the telnet daemon. 558 */ 559 if (tip->type != T_DATA_IND && 560 tip->type != T_EXDATA_IND) 561 tmip->flags &= ~TEL_GETBLK; 562 563 switch (tip->type) { 564 case T_ORDREL_IND: 565 case T_DISCON_IND: 566 /* Make into M_HANGUP and putnext */ 567 ASSERT(mp->b_cont == NULL); 568 mp->b_datap->db_type = M_HANGUP; 569 mp->b_wptr = mp->b_rptr; 570 if (mp->b_cont) { 571 freemsg(mp->b_cont); 572 mp->b_cont = NULL; 573 } 574 /* 575 * If we haven't already, send T_UNBIND_REQ 576 * to prevent TCP from going into "BOUND" 577 * state and locking up the port. 578 */ 579 if (tip->type == T_DISCON_IND && 580 tmip->unbind_mp != NULL) { 581 putnext(q, mp); 582 qreply(q, tmip->unbind_mp); 583 tmip->unbind_mp = NULL; 584 } else { 585 putnext(q, mp); 586 } 587 break; 588 589 case T_DATA_IND: /* conform to TPI, but never happens */ 590 case T_EXDATA_IND: 591 newmp = mp->b_cont; 592 freeb(mp); 593 mp = newmp; 594 if (mp) { 595 ASSERT(mp->b_datap->db_type == M_DATA); 596 if (msgdsize(mp) != 0) { 597 goto is_mdata; 598 } 599 freemsg(mp); 600 } 601 break; 602 603 /* 604 * We only get T_OK_ACK when we issue the unbind, and 605 * it can be ignored safely. 606 */ 607 case T_OK_ACK: 608 ASSERT(tmip->unbind_mp == NULL); 609 freemsg(mp); 610 break; 611 612 default: 613 #ifdef DEBUG 614 cmn_err(CE_NOTE, 615 "telmodrsrv: unexpected TLI primitive " 616 "msg type 0x%x", tip->type); 617 #endif 618 freemsg(mp); 619 } 620 break; 621 622 case M_SETOPTS: 623 putnext(q, mp); 624 break; 625 626 default: 627 #ifdef DEBUG 628 cmn_err(CE_NOTE, 629 "telmodrsrv: unexpected msg type 0x%x", 630 mp->b_datap->db_type); 631 #endif 632 freemsg(mp); 633 } 634 } 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 void 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 } 854 855 /* 856 * telmodwsrv - module write service procedure 857 */ 858 static void 859 telmodwsrv(queue_t *q) 860 { 861 mblk_t *mp, *savemp; 862 863 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 864 865 while ((mp = getq(q)) != NULL) { 866 if (!canputnext(q)) { 867 ASSERT(mp->b_datap->db_type < QPCTL); 868 (void) putbq(q, mp); 869 return; 870 } 871 switch (mp->b_datap->db_type) { 872 873 case M_DATA: 874 if (tmip->flags & TEL_STOPPED) { 875 (void) putbq(q, mp); 876 return; 877 } 878 /* 879 * Insert a null character if carraige return 880 * is not followed by line feed 881 */ 882 if (!snd_parse(q, mp)) { 883 return; 884 } 885 break; 886 887 case M_CTL: 888 if (((mp->b_wptr - mp->b_rptr) == 1) && 889 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) { 890 savemp = mp->b_cont; 891 freeb(mp); 892 mp = savemp; 893 } 894 putnext(q, mp); 895 break; 896 897 case M_PROTO: 898 putnext(q, mp); 899 break; 900 901 default: 902 #ifdef DEBUG 903 cmn_err(CE_NOTE, 904 "telmodwsrv: unexpected msg type 0x%x", 905 mp->b_datap->db_type); 906 #endif 907 freemsg(mp); 908 } 909 910 } 911 } 912 913 /* 914 * This routine is called from read put/service procedure and parses 915 * message block to check for telnet protocol by detecting an IAC. 916 * The routine processes the data part of the message block first and 917 * then sends protocol followed after IAC to the telnet daemon. The 918 * routine also processes CR/LF by eliminating LF/NULL followed after CR. 919 * 920 * Since the code to do this with streams mblks is complicated, some 921 * explanations are in order. If an IAC is found, a dupb() is done, 922 * and the pointers are adjusted to create two streams message. The 923 * (possibly empty) first message contains preceeding data, and the 924 * second begins with the IAC and contains the rest of the streams 925 * message. 926 * 927 * The variables: 928 * datamp: Points to the head of a chain of mblks containing data 929 * which requires no expansion, and can be forwarded directly 930 * to the pty. 931 * prevmp: Points to the last mblk on the datamp chain, used to add 932 * to the chain headed by datamp. 933 * newmp: When an M_CTL header is required, this pointer references 934 * that "header" mblk. 935 * protomp: When an IAC is discovered, a dupb() is done on the first mblk 936 * containing an IAC. protomp points to this dup'ed mblk. 937 * This mblk is eventually forwarded to the daemon. 938 */ 939 static int 940 rcv_parse(queue_t *q, mblk_t *mp) 941 { 942 mblk_t *protomp, *newmp, *datamp, *prevmp; 943 unsigned char *tmp; 944 size_t msgsize; 945 946 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 947 948 datamp = mp; 949 prevmp = protomp = 0; 950 951 while (mp) { 952 /* 953 * If the mblk is empty, just continue scanning. 954 */ 955 if (mp->b_rptr == mp->b_wptr) { 956 prevmp = mp; 957 mp = mp->b_cont; 958 continue; 959 } 960 /* 961 * First check to see if we have received CR and are checking 962 * for a following LF/NULL. If so, do what's necessary to 963 * trim the LF/NULL. This case is for when the LF/NULL is 964 * at the beginning of a subsequent mblk. 965 */ 966 if (!(tmip->flags & TEL_BINARY_IN) && 967 (tmip->flags & TEL_CRRCV)) { 968 if ((*mp->b_rptr == '\n') || (*mp->b_rptr == NULL)) { 969 if (mp->b_wptr == (mp->b_rptr + 1)) { 970 tmip->flags &= ~TEL_CRRCV; 971 if (prevmp) { 972 prevmp->b_cont = mp->b_cont; 973 freeb(mp); 974 mp = prevmp->b_cont; 975 continue; 976 } else { 977 datamp = mp->b_cont; 978 freeb(mp); 979 if (datamp == NULL) { 980 /* 981 * Message contained 982 * only a '\0' after 983 * a '\r' in a previous 984 * message, so we can 985 * read more, even 986 * though we have 987 * nothing to putnext. 988 */ 989 return (1); 990 } else { 991 mp = datamp; 992 continue; 993 } 994 } 995 } 996 mp->b_rptr += 1; 997 } 998 tmip->flags &= ~TEL_CRRCV; 999 } 1000 tmp = mp->b_rptr; 1001 /* 1002 * Now scan through the entire message block, for IACs 1003 * and CR characters, which need processing. 1004 */ 1005 while (tmp < mp->b_wptr) { 1006 1007 if (tmp[0] == IAC) { 1008 /* 1009 * Telnet protocol - parse it now 1010 * process data part of mblk 1011 * before sending the protocol. 1012 */ 1013 if (tmp > mp->b_rptr) { 1014 if ((protomp = dupb(mp)) == NULL) { 1015 msgsize = msgdsize(datamp); 1016 recover(q, datamp, msgsize); 1017 return (0); 1018 } 1019 ASSERT(tmp >= mp->b_datap->db_base); 1020 ASSERT(tmp <= mp->b_datap->db_lim); 1021 ASSERT(tmp >= 1022 protomp->b_datap->db_base); 1023 ASSERT(tmp <= protomp->b_datap->db_lim); 1024 mp->b_wptr = tmp; 1025 protomp->b_rptr = tmp; 1026 protomp->b_cont = mp->b_cont; 1027 mp->b_cont = 0; 1028 1029 if (prevmp) 1030 prevmp->b_cont = mp; 1031 1032 } else { 1033 protomp = mp; 1034 1035 if (prevmp) 1036 prevmp->b_cont = 0; 1037 else 1038 datamp = 0; 1039 } 1040 if (datamp) { 1041 putnext(q, datamp); 1042 } 1043 /* 1044 * create a 1 byte M_CTL message block with 1045 * protomp and send it down. 1046 */ 1047 1048 if ((newmp = allocb(sizeof (char), 1049 BPRI_MED)) == NULL) { 1050 /* 1051 * Save the dup'ed mp containing 1052 * the protocol information which 1053 * we couldn't get an M_CTL header 1054 * for. 1055 */ 1056 msgsize = msgdsize(protomp); 1057 recover(q, protomp, msgsize); 1058 return (0); 1059 } 1060 newmp->b_datap->db_type = M_CTL; 1061 newmp->b_wptr = newmp->b_rptr + 1; 1062 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER; 1063 newmp->b_cont = protomp; 1064 noenable(q); 1065 tmip->flags |= TEL_STOPPED; 1066 putnext(q, newmp); 1067 1068 return (0); 1069 } 1070 if (!(tmip->flags & TEL_BINARY_IN)) { 1071 /* 1072 * Set TEL_CRRCV flag if last character is CR 1073 */ 1074 if ((tmp == (mp->b_wptr - 1)) && 1075 (tmp[0] == '\r')) { 1076 tmip->flags |= TEL_CRRCV; 1077 break; 1078 } 1079 1080 /* 1081 * If CR is followed by LF/NULL, get rid of 1082 * LF/NULL and realign the message block. 1083 */ 1084 if ((tmp[0] == '\r') && ((tmp[1] == '\n') || 1085 (tmp[1] == NULL))) { 1086 /* 1087 * If CR is in the middle of a block, 1088 * we need to get rid of LF and join 1089 * the two pieces together. 1090 */ 1091 if (mp->b_wptr > (tmp + 2)) { 1092 bcopy(tmp + 2, tmp + 1, 1093 (mp->b_wptr - tmp - 2)); 1094 mp->b_wptr -= 1; 1095 } else { 1096 mp->b_wptr = tmp + 1; 1097 } 1098 1099 if (prevmp) 1100 prevmp->b_cont = mp; 1101 } 1102 } 1103 tmp++; 1104 } 1105 prevmp = mp; 1106 mp = mp->b_cont; 1107 } 1108 putnext(q, datamp); 1109 1110 return (1); 1111 } 1112 1113 /* 1114 * This routine is called from write put/service procedures and processes 1115 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are 1116 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk. 1117 * This routine is pessimistic: It pre-allocates a buffer twice the size 1118 * of the incoming message, which is the maximum size a message can become 1119 * after IAC expansion. 1120 * 1121 * savemp: Points at the original message, so it can be freed when 1122 * processing is complete. 1123 * mp: The current point of scanning the message. 1124 * newmp: New message being created with the processed output. 1125 */ 1126 static int 1127 snd_parse(queue_t *q, mblk_t *mp) 1128 { 1129 unsigned char *tmp, *tmp1; 1130 mblk_t *newmp, *savemp; 1131 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1132 size_t size = msgdsize(mp); 1133 1134 savemp = mp; 1135 1136 if (size == 0) { 1137 putnext(q, mp); 1138 return (1); 1139 } 1140 1141 /* 1142 * Extra byte to allocb() takes care of the case when there was 1143 * a '\r' at the end of the previous message and there's a '\r' 1144 * at the beginning of the current message. 1145 */ 1146 if ((newmp = allocb((2 * size)+1, BPRI_MED)) == NULL) { 1147 recover(q, mp, (2 * size)+1); 1148 return (0); 1149 } 1150 newmp->b_datap->db_type = M_DATA; 1151 1152 tmp1 = newmp->b_rptr; 1153 while (mp) { 1154 if (!(tmip->flags & TEL_BINARY_OUT) && 1155 (tmip->flags & TEL_CRSND)) { 1156 if (*(mp->b_rptr) != '\n') 1157 *tmp1++ = NULL; 1158 tmip->flags &= ~TEL_CRSND; 1159 } 1160 tmp = mp->b_rptr; 1161 while (tmp < mp->b_wptr) { 1162 if (!(tmip->flags & TEL_BINARY_OUT)) { 1163 *tmp1++ = *tmp; 1164 if ((tmp == (mp->b_wptr - 1)) && 1165 (tmp[0] == '\r')) { 1166 tmip->flags |= TEL_CRSND; 1167 break; 1168 } 1169 if ((tmp[0] == '\r') && 1170 (tmp1 == newmp->b_wptr)) { 1171 /* XXX.sparker: can't happen */ 1172 tmip->flags |= TEL_CRSND; 1173 break; 1174 } 1175 if ((tmp[0] == '\r') && (tmp[1] != '\n')) { 1176 *tmp1++ = NULL; 1177 } 1178 } else 1179 *tmp1++ = *tmp; 1180 1181 if (tmp[0] == IAC) { 1182 *tmp1++ = IAC; 1183 } 1184 tmp++; 1185 } 1186 mp = mp->b_cont; 1187 } 1188 1189 newmp->b_wptr = tmp1; 1190 1191 putnext(q, newmp); 1192 freemsg(savemp); 1193 return (1); 1194 } 1195 1196 static void 1197 telmod_timer(void *arg) 1198 { 1199 queue_t *q = arg; 1200 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1201 1202 ASSERT(tmip); 1203 1204 if (q->q_flag & QREADR) { 1205 ASSERT(tmip->rtimoutid); 1206 tmip->rtimoutid = 0; 1207 } else { 1208 ASSERT(tmip->wtimoutid); 1209 tmip->wtimoutid = 0; 1210 } 1211 enableok(q); 1212 qenable(q); 1213 } 1214 1215 static void 1216 telmod_buffer(void *arg) 1217 { 1218 queue_t *q = arg; 1219 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1220 1221 ASSERT(tmip); 1222 1223 if (q->q_flag & QREADR) { 1224 ASSERT(tmip->rbufcid); 1225 tmip->rbufcid = 0; 1226 } else { 1227 ASSERT(tmip->wbufcid); 1228 tmip->wbufcid = 0; 1229 } 1230 enableok(q); 1231 qenable(q); 1232 } 1233 1234 static void 1235 recover(queue_t *q, mblk_t *mp, size_t size) 1236 { 1237 bufcall_id_t bid; 1238 timeout_id_t tid; 1239 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; 1240 1241 ASSERT(mp->b_datap->db_type < QPCTL); 1242 noenable(q); 1243 (void) putbq(q, mp); 1244 1245 /* 1246 * Make sure there is at most one outstanding request per queue. 1247 */ 1248 if (q->q_flag & QREADR) { 1249 if (tmip->rtimoutid || tmip->rbufcid) { 1250 return; 1251 } 1252 } else { 1253 if (tmip->wtimoutid || tmip->wbufcid) { 1254 return; 1255 } 1256 } 1257 if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) { 1258 tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT); 1259 if (q->q_flag & QREADR) 1260 tmip->rtimoutid = tid; 1261 else 1262 tmip->wtimoutid = tid; 1263 } else { 1264 if (q->q_flag & QREADR) 1265 tmip->rbufcid = bid; 1266 else 1267 tmip->wbufcid = bid; 1268 } 1269 } 1270