xref: /illumos-gate/usr/src/uts/common/io/telmod.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
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