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